-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathfunctional.tcc
137 lines (117 loc) · 4.71 KB
/
functional.tcc
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
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
#define functional_tcc
#include "functional.h"
namespace kaiu {
namespace detail {
template <typename Result, typename Functor, typename Args>
Result invoke_with_tuple(Functor func, Args tuple)
{
constexpr auto ArgCount = std::tuple_size<Args>::value;
return invoke_shuffle_args<Result, Functor, Args, ArgCount>
(func, std::make_index_sequence<ArgCount>(), std::forward<Args>(tuple));
}
template <typename Result, typename Functor, typename Args, size_t ArgCount, size_t... Indices>
Result invoke_shuffle_args(Functor func, std::index_sequence<Indices...> indices, Args tuple)
{
return func(std::get<Indices>(std::forward<Args>(tuple))...);
}
/*** CurriedFunction ***/
template <typename Result, size_t Arity, typename Functor, typename... CurriedArgs>
CurriedFunction<Result, Arity, Functor, CurriedArgs...>
::CurriedFunction(Functor func) :
func(func)
{
}
template <typename Result, size_t Arity, typename Functor, typename... CurriedArgs>
CurriedFunction<Result, Arity, Functor, CurriedArgs...>
::CurriedFunction(Functor func, const std::tuple<CurriedArgs...>& curried_args) :
func(func),
curried_args(curried_args)
{
}
template <typename Result, size_t Arity, typename Functor, typename... CurriedArgs>
template <typename... ExtraArgs>
CurriedFunction<Result, Arity, Functor, CurriedArgs..., ExtraArgs...>
CurriedFunction<Result, Arity, Functor, CurriedArgs...>
::apply (ExtraArgs&&... extra_args) const
{
constexpr auto NumArgs = sizeof...(CurriedArgs) + sizeof...(ExtraArgs);
static_assert(NumArgs <= Arity,
"Cannot curry function: too many arguments specified");
return CurriedFunction<Result, Arity, Functor,
CurriedArgs..., ExtraArgs...>(func,
tuple_cat(
curried_args,
std::forward_as_tuple(extra_args...)));
}
template <typename Result, size_t Arity, typename Functor, typename... CurriedArgs>
template <typename Arg>
CurriedFunction<Result, Arity, Functor, CurriedArgs..., Arg&>
CurriedFunction<Result, Arity, Functor, CurriedArgs...>
::operator << (std::reference_wrapper<Arg> ref) const
{
return apply(ref.get());
}
template <typename Result, size_t Arity, typename Functor, typename... CurriedArgs>
template <typename Arg>
CurriedFunction<Result, Arity, Functor, CurriedArgs..., typename std::decay<Arg>::type>
CurriedFunction<Result, Arity, Functor, CurriedArgs...>
::operator << (Arg&& arg) const
{
return apply(static_cast<typename std::decay<Arg>::type>(arg));
}
template <typename Result, size_t Arity, typename Functor, typename... CurriedArgs>
template <typename... ExtraArgs>
typename std::enable_if<(sizeof...(ExtraArgs) > 0), Result>::type
CurriedFunction<Result, Arity, Functor, CurriedArgs...>
::operator () (ExtraArgs&&... extra_args) const
{
statically_check_args_count_for_invoke<sizeof...(CurriedArgs) + sizeof...(ExtraArgs)>();
return apply(std::forward<ExtraArgs>(extra_args)...)
.invoke();
}
template <typename Result, size_t Arity, typename Functor, typename... CurriedArgs>
template <typename... ExtraArgs>
typename std::enable_if<(sizeof...(ExtraArgs) == 0), Result>::type
CurriedFunction<Result, Arity, Functor, CurriedArgs...>
::operator () (ExtraArgs&&... extra_args) const
{
statically_check_args_count_for_invoke<sizeof...(CurriedArgs) + sizeof...(ExtraArgs)>();
return invoke();
}
template <typename Result, size_t Arity, typename Functor, typename... CurriedArgs>
template <size_t Arity_>
typename std::enable_if<(sizeof...(CurriedArgs) == Arity_), Result>::type
CurriedFunction<Result, Arity, Functor, CurriedArgs...>
::invoke () const
{
statically_check_args_count_for_invoke<sizeof...(CurriedArgs)>();
return invoke_with_tuple<Result, Functor, ArgsTuple>(func, curried_args);
}
template <typename Result, size_t Arity, typename Functor, typename... CurriedArgs>
template <size_t NumArgs>
void CurriedFunction<Result, Arity, Functor, CurriedArgs...>
::statically_check_args_count_for_invoke() const
{
static_assert(NumArgs >= Arity, "Cannot invoke curried function, not enough arguments curried/passed to it at time of invocation");
static_assert(NumArgs <= Arity, "Cannot invoke curried function, too many arguments curried/passed to it at time of invocation");
}
template <typename Result, size_t Arity, typename Functor, typename... CurriedArgs>
bool CurriedFunction<Result, Arity, Functor, CurriedArgs...>
::operator == (nullptr_t) const
{
return false;
}
template <typename Result, size_t Arity, typename Functor, typename... CurriedArgs>
bool CurriedFunction<Result, Arity, Functor, CurriedArgs...>
::operator != (nullptr_t) const
{
return !operator ==(nullptr);
}
} /* end namespace detail */
template <typename Result, typename Functor, typename Args>
Result invoke(Functor func, Args args)
{
return detail::invoke_with_tuple<Result, Functor, Args>
(func, std::forward<Args>(args));
}
}