-
Notifications
You must be signed in to change notification settings - Fork 73
/
algos-std.hxx
133 lines (103 loc) · 3.21 KB
/
algos-std.hxx
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
#pragma once
#include <utility>
using std::size_t;
namespace algo {
// Transform
// (t, f) => (f(t_0),f(t_1),...,f(t_n))
namespace detail {
template<typename F, typename Tup, size_t... Is>
constexpr auto transform(F f, Tup&& tup, std::index_sequence<Is...>) {
return std::make_tuple(f(std::get<Is>(std::forward<Tup>(tup)))...);
}
template<typename F, typename Tup1, typename Tup2, size_t... Is>
constexpr auto transform(F f, Tup1&& tup1, Tup2&& tup2, std::index_sequence<Is...>) {
return std::make_tuple(f(
std::get<Is>(std::forward<Tup1>(tup1)),
std::get<Is>(std::forward<Tup2>(tup2))
)...);
}
} // namespace detail
template<typename F, typename Tup>
constexpr auto transform(F f, Tup&& tup) {
return detail::transform(
f,
std::forward<Tup>(tup),
std::make_index_sequence<std::tuple_size_v<std::remove_reference_t<Tup>>>()
);
}
template<typename F, typename Tup1, typename Tup2>
constexpr auto transform(F f, Tup1&& tup1, Tup2&& tup2) {
static_assert(
std::tuple_size_v<std::remove_reference_t<Tup1>> ==
std::tuple_size_v<std::remove_reference_t<Tup2>>);
return detail::transform(
f,
std::forward<Tup1>(tup1),
std::forward<Tup2>(tup2),
std::make_index_sequence<std::tuple_size_v<std::remove_reference_t<Tup1>>>()
);
}
// Fold
// (t, v, f) => f(...f(f(v,t_0),t_1),...,t_n)
namespace detail {
// Overload for empty tuple.
template<typename Tup, typename V, typename F>
constexpr auto fold(Tup&& tup, V&& v, F f, std::index_sequence<>) {
return std::forward<V>(v);
}
// Overload for non-empty tuple.
template<typename Tup, typename V, typename F, size_t I, size_t... Is>
constexpr auto fold(Tup&& tup, V&& v, F f, std::index_sequence<I, Is...>) {
if constexpr(sizeof...(Is) == 0) {
// Fold the remaining element with the accumulated value.
return f(std::forward<V>(v), std::get<I>(std::forward<Tup>(tup)));
} else {
// Left-recurse.
return fold(
std::forward<Tup>(tup),
f(std::forward<V>(v), std::get<I>(std::forward<Tup>(tup))),
f,
std::index_sequence<Is...>()
);
}
}
} // namespace detail
template<typename Tup, typename V, typename F>
constexpr auto fold(Tup&& tup, V&& v, F f) {
return detail::fold(
std::forward<Tup>(tup),
std::forward<V>(v),
f,
std::make_index_sequence<std::tuple_size_v<std::remove_reference_t<Tup>>>()
);
}
// Take
// Takes elements in the range [Begin, End)
namespace detail {
template<size_t Begin, typename Tup, size_t... Is>
constexpr auto take(Tup&& tup, std::index_sequence<Is...>) {
return std::make_tuple(std::get<Begin + Is>(std::forward<Tup>(tup))...);
}
} // namespace detail
template<size_t Begin, size_t End, typename Tup>
constexpr auto take(Tup&& tup) {
return detail::take<Begin>(
std::forward<Tup>(tup),
std::make_index_sequence<End - Begin>()
);
}
// Repeat
// Make a tuple with N instances of x.
namespace detail {
template<typename X, size_t... Is>
constexpr auto repeat(const X& x, std::index_sequence<Is...>) {
return std::make_tuple((void(Is), x)...);
}
} // namespace detail
template<size_t N, typename X>
constexpr auto repeat(const X& x) {
return detail::repeat(x, std::make_index_sequence<N>());
}
// Concatenate
using std::tuple_cat;
} // namespace algo