-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcurry.h
79 lines (61 loc) · 2.97 KB
/
curry.h
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
#ifndef CURRY_H
#define CURRY_H
#include <utility>
#include <tuple>
#include <functional>
#include <type_traits>
#include "cpp17.h"
namespace detail {
template <typename F, typename... CapturedArgs>
class curried_fn {
public:
curried_fn(const F& f)
: _f{f}
, _capturedArgs{std::make_tuple()} {
}
curried_fn(const F&& f)
: _f{std::move(f)} {
}
curried_fn(const F& f, const std::tuple<CapturedArgs...>& capturedArgs)
: _f{f}
, _capturedArgs{capturedArgs} {
}
template <typename Arg, typename... Args>
auto operator()(Arg&& arg, Args&&... args) const -> std::enable_if_t<!is_callable<F(CapturedArgs..., Arg, Args...)>::value, curried_fn<F, CapturedArgs..., std::decay_t<Arg>, std::decay_t<Args>...>> {
return curried_fn<F, CapturedArgs..., std::decay_t<Arg>, std::decay_t<Args>...>(_f, std::tuple_cat(_capturedArgs, std::make_tuple(arg, args...)));
}
template <typename... Args>
auto operator()(Args&&... args) const -> std::enable_if_t<is_callable<F(CapturedArgs..., Args...)>::value, std::remove_reference_t<std::result_of_t<F(CapturedArgs..., Args...)>>> {
return apply(_f, _capturedArgs, std::make_tuple(std::forward<Args>(args)...));
}
template <typename Arg, typename... Args>
auto operator()(Arg&& arg, Args&&... args) -> std::enable_if_t<!is_callable<F(CapturedArgs..., Arg, Args...)>::value, curried_fn<std::remove_const_t<F>, CapturedArgs..., std::decay_t<Arg>, std::decay_t<Args>...>> {
return curried_fn<std::remove_const_t<F>, CapturedArgs..., std::decay_t<Arg>, std::decay_t<Args>...>(std::move(_f), std::tuple_cat(std::move(_capturedArgs), std::make_tuple(arg, args...)));
}
template <typename... Args>
auto operator()(Args&&... args) -> std::enable_if_t<is_callable<F(CapturedArgs..., Args...)>::value, std::result_of_t<F(CapturedArgs..., Args...)>> {
return apply(std::move(_f), std::move(_capturedArgs), std::make_tuple(std::forward<Args>(args)...));
}
private:
F _f;
std::tuple<CapturedArgs...> _capturedArgs;
};
} // namespace detail
namespace traits {
template <typename>
struct is_curried_fn : std::false_type {};
template <typename F, typename... Args>
struct is_curried_fn<detail::curried_fn<F, Args...>> : std::true_type {};
template <typename T>
constexpr bool is_curried_fn_v = is_curried_fn<std::remove_reference_t<T>>::value;
} // namespace traits
template <typename F>
auto curry(F&& f) -> std::enable_if_t<!traits::is_curried_fn_v<F>, detail::curried_fn<std::remove_const_t<std::remove_reference_t<F>>>> {
detail::curried_fn<std::remove_const_t<std::remove_reference_t<F>>> retVal(std::forward<F>(f));
return retVal;
}
template <typename F, typename... Args>
detail::curried_fn<F, Args...> curry(const detail::curried_fn<F, Args...>& curriedFn) {
return curriedFn;
}
#endif