mpc
Haskell-like feature supports in C++
partial.hpp
Go to the documentation of this file.
1
2#pragma once
3#include <functional> // std::invoke
6
7// clang-format off
8
9namespace mpc {
10 // partial
11 // https://github.com/llvm/llvm-project/blob/main/libcxx/include/__functional/perfect_forward.h
12
14 template <copy_constructible_object Op, class... Bound>
15 struct partial;
16
17 template <class T>
18 inline constexpr bool is_partial_v = false;
19
20 template <copy_constructible_object Op, class... Bound>
21 inline constexpr bool is_partial_v<partial<Op, Bound...>> = true;
22
23 template <class Op, class Tuple, std::size_t... Idx, class... Args>
24 constexpr auto make_partial_impl(Op&& op, Tuple&& tuple, std::index_sequence<Idx...>, Args&&... args) noexcept(
25 noexcept( partial(std::forward<Op>(op), std::get<Idx>(std::forward<Tuple>(tuple))..., std::forward<Args>(args)...)))
26 -> decltype(partial(std::forward<Op>(op), std::get<Idx>(std::forward<Tuple>(tuple))..., std::forward<Args>(args)...)) {
27 return partial(std::forward<Op>(op), std::get<Idx>(std::forward<Tuple>(tuple))..., std::forward<Args>(args)...);
28 }
29
30 template <class Op, class... Args,
31 class = std::enable_if_t<is_partial_v<std::remove_cvref_t<Op>>>>
32 constexpr auto make_partial(Op&& op, Args&&... args) noexcept(
33 noexcept( make_partial_impl(forward_like<Op>(op.op_), forward_like<Op>(op.bound_), std::make_index_sequence<std::tuple_size_v<decltype(op.bound_)>>(), std::forward<Args>(args)...)))
34 -> decltype(make_partial_impl(forward_like<Op>(op.op_), forward_like<Op>(op.bound_), std::make_index_sequence<std::tuple_size_v<decltype(op.bound_)>>(), std::forward<Args>(args)...)) {
35 return make_partial_impl(forward_like<Op>(op.op_), forward_like<Op>(op.bound_), std::make_index_sequence<std::tuple_size_v<decltype(op.bound_)>>(), std::forward<Args>(args)...);
36 }
37
38 template <class Op, class... Args,
39 class = std::enable_if_t<!is_partial_v<std::remove_cvref_t<Op>>>>
40 constexpr auto make_partial(Op&& op, Args&&... args) noexcept(
41 noexcept( partial(std::forward<Op>(op), std::forward<Args>(args)...)))
42 -> decltype(partial(std::forward<Op>(op), std::forward<Args>(args)...)) {
43 return partial(std::forward<Op>(op), std::forward<Args>(args)...);
44 }
45
46 template <class Op, class Tuple, std::size_t... Idx, class... Args,
47 class = std::enable_if_t<std::is_invocable_v<Op, forward_like_t<Tuple, std::tuple_element_t<Idx, std::remove_cvref_t<Tuple>>>..., Args...>>>
48 constexpr auto __call(Op&& op, Tuple&& tuple, std::index_sequence<Idx...>, Args&&... args) noexcept(
49 noexcept( std::invoke(std::forward<Op>(op), std::get<Idx>(std::forward<Tuple>(tuple))..., std::forward<Args>(args)...)))
50 -> decltype(std::invoke(std::forward<Op>(op), std::get<Idx>(std::forward<Tuple>(tuple))..., std::forward<Args>(args)...)) {
51 return std::invoke(std::forward<Op>(op), std::get<Idx>(std::forward<Tuple>(tuple))..., std::forward<Args>(args)...);
52 }
53
54 template <class Op, class Tuple, std::size_t... Idx, class... Args,
55 class = std::enable_if_t<!std::is_invocable_v<Op, forward_like_t<Tuple, std::tuple_element_t<Idx, std::remove_cvref_t<Tuple>>>..., Args...>>>
56 constexpr auto __call(Op&& op, Tuple&& tuple, std::index_sequence<Idx...>, Args&&... args) noexcept(
57 noexcept( partial(std::forward<Op>(op), std::get<Idx>(std::forward<Tuple>(tuple))..., std::forward<Args>(args)...)))
58 -> decltype(partial(std::forward<Op>(op), std::get<Idx>(std::forward<Tuple>(tuple))..., std::forward<Args>(args)...)) {
59 return partial(std::forward<Op>(op), std::get<Idx>(std::forward<Tuple>(tuple))..., std::forward<Args>(args)...);
60 }
61
62 template <copy_constructible_object Op, class... Bound>
63 struct partial {
64 private:
65 copyable_box<Op> op_{};
66 std::tuple<Bound...> bound_{};
67
68 template <class Op2, class... Args, class>
69 friend constexpr auto make_partial(Op2&&, Args&&...);
70
71 public:
72 constexpr explicit partial()
73 requires std::default_initializable<Op> and (std::default_initializable<Bound> and ...) = default;
74
75 template <class... BoundArgs,
76 class = std::enable_if_t<std::is_constructible_v<std::tuple<Bound...>, BoundArgs&&...>>>
77 constexpr explicit partial(Op const& op, BoundArgs&&... bound)
78 : op_(std::in_place, op), bound_(std::forward<BoundArgs>(bound)...) {}
79
80 template <class... BoundArgs,
81 class = std::enable_if_t<std::is_constructible_v<std::tuple<Bound...>, BoundArgs&&...>>>
82 constexpr explicit partial(Op&& op, BoundArgs&&... bound)
83 : op_(std::in_place, std::move(op)), bound_(std::forward<BoundArgs>(bound)...) {}
84
85 partial(partial const&) = default;
86 partial(partial&&) = default;
87
88 partial& operator=(partial const&) = default;
89 partial& operator=(partial&&) = default;
90
91 // operator()
92 template <class... Args>
93 constexpr auto operator()(Args&&... args) & noexcept(
94 noexcept( __call(*op_, bound_, std::index_sequence_for<Bound...>(), std::forward<Args>(args)...)))
95 -> decltype(__call(*op_, bound_, std::index_sequence_for<Bound...>(), std::forward<Args>(args)...)) {
96 return __call(*op_, bound_, std::index_sequence_for<Bound...>(), std::forward<Args>(args)...);
97 }
98
99 template <class... Args>
100 constexpr auto operator()(Args&&... args) const& noexcept(
101 noexcept( __call(*op_, bound_, std::index_sequence_for<Bound...>(), std::forward<Args>(args)...)))
102 -> decltype(__call(*op_, bound_, std::index_sequence_for<Bound...>(), std::forward<Args>(args)...)) {
103 return __call(*op_, bound_, std::index_sequence_for<Bound...>(), std::forward<Args>(args)...);
104 }
105
106 template <class... Args>
107 constexpr auto operator()(Args&&... args) && noexcept(
108 noexcept( __call(*std::move(op_), std::move(bound_), std::index_sequence_for<Bound...>(), std::forward<Args>(args)...)))
109 -> decltype(__call(*std::move(op_), std::move(bound_), std::index_sequence_for<Bound...>(), std::forward<Args>(args)...)) {
110 return __call(*std::move(op_), std::move(bound_), std::index_sequence_for<Bound...>(), std::forward<Args>(args)...);
111 }
112
113 template <class... Args>
114 constexpr auto operator()(Args&&... args) const&& noexcept(
115 noexcept( __call(*std::move(op_), std::move(bound_), std::index_sequence_for<Bound...>(), std::forward<Args>(args)...)))
116 -> decltype(__call(*std::move(op_), std::move(bound_), std::index_sequence_for<Bound...>(), std::forward<Args>(args)...)) {
117 return __call(*std::move(op_), std::move(bound_), std::index_sequence_for<Bound...>(), std::forward<Args>(args)...);
118 }
119
120 // operator%
121 template <class Arg>
122 constexpr auto operator%(Arg&& arg) & noexcept(
123 noexcept( (*this)(std::forward<Arg>(arg))))
124 -> decltype((*this)(std::forward<Arg>(arg))) {
125 return (*this)(std::forward<Arg>(arg));
126 }
127
128 template <class Arg>
129 constexpr auto operator%(Arg&& arg) const& noexcept(
130 noexcept( (*this)(std::forward<Arg>(arg))))
131 -> decltype((*this)(std::forward<Arg>(arg))) {
132 return (*this)(std::forward<Arg>(arg));
133 }
134
135 template <class Arg>
136 constexpr auto operator%(Arg&& arg) && noexcept(
137 noexcept( std::move(*this)(std::forward<Arg>(arg))))
138 -> decltype(std::move(*this)(std::forward<Arg>(arg))) {
139 return std::move(*this)(std::forward<Arg>(arg));
140 }
141
142 template <class Arg>
143 constexpr auto operator%(Arg&& arg) const&& noexcept(
144 noexcept( std::move(*this)(std::forward<Arg>(arg))))
145 -> decltype(std::move(*this)(std::forward<Arg>(arg))) {
146 return std::move(*this)(std::forward<Arg>(arg));
147 }
148 };
149
151 template <class Op, class... Args>
152 partial(Op, Args...) -> partial<Op, Args...>;
153} // namespace mpc
154
155// clang-format on
Makes copy_constructible but not copy_assignable types copy_assignable.
Definition: copyable_box.hpp:28
partial(Op, Args...) -> partial< Op, Args... >
A deduction guide for partial.
Implements a perfect-forwarding call wrapper.
Definition: partial.hpp:63