Skip to content

Commit 1f41575

Browse files
qchateauldionne
authored andcommitted
[sort] implemented as merge sort
replaced the insersion sort by a merge sort reduces compilation time, memory usage and template recursion depth
1 parent be0640b commit 1f41575

File tree

1 file changed

+154
-54
lines changed

1 file changed

+154
-54
lines changed

include/boost/hana/sort.hpp

Lines changed: 154 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -68,82 +68,182 @@ BOOST_HANA_NAMESPACE_BEGIN
6868
));
6969
};
7070

71-
template <typename Pred, std::size_t Insert, bool IsInsertionPoint,
72-
typename Left,
73-
std::size_t ...Right>
74-
struct insert;
71+
template <typename Left, typename Right>
72+
struct concat;
73+
74+
template <std::size_t ...l, std::size_t ...r>
75+
struct concat<std::index_sequence<l...>, std::index_sequence<r...>> {
76+
using type = std::index_sequence<l..., r...>;
77+
};
78+
79+
template <typename Pred, bool PickRight, typename Left, typename Right>
80+
struct merge;
7581

76-
// We did not find the insertion point; continue processing elements
77-
// recursively.
7882
template <
79-
typename Pred, std::size_t Insert,
80-
std::size_t ...Left,
81-
std::size_t Right1, std::size_t Right2, std::size_t ...Right
82-
>
83-
struct insert<Pred, Insert, false,
84-
std::index_sequence<Left...>,
85-
Right1, Right2, Right...
83+
typename Pred,
84+
std::size_t l0,
85+
std::size_t l1,
86+
std::size_t ...l,
87+
std::size_t r0,
88+
std::size_t ...r>
89+
struct merge<
90+
Pred,
91+
false,
92+
std::index_sequence<l0, l1, l...>,
93+
std::index_sequence<r0, r...>
8694
> {
87-
using type = typename insert<
88-
Pred, Insert, (bool)Pred::template apply<Insert, Right2>::value,
89-
std::index_sequence<Left..., Right1>,
90-
Right2, Right...
95+
using type = typename concat<
96+
std::index_sequence<l0>,
97+
typename merge<
98+
Pred,
99+
(bool)Pred::template apply<r0, l1>::value,
100+
std::index_sequence<l1, l...>,
101+
std::index_sequence<r0, r...>
102+
>::type
91103
>::type;
92104
};
93105

94-
// We did not find the insertion point, but there is only one element
95-
// left. We insert at the end of the list, and we're done.
96-
template <typename Pred, std::size_t Insert, std::size_t ...Left, std::size_t Last>
97-
struct insert<Pred, Insert, false, std::index_sequence<Left...>, Last> {
98-
using type = std::index_sequence<Left..., Last, Insert>;
106+
template <
107+
typename Pred,
108+
std::size_t l0,
109+
std::size_t r0,
110+
std::size_t ...r>
111+
struct merge<
112+
Pred,
113+
false,
114+
std::index_sequence<l0>,
115+
std::index_sequence<r0, r...>
116+
> {
117+
using type = std::index_sequence<l0, r0, r...>;
99118
};
100119

101-
// We found the insertion point, we're done.
102-
template <typename Pred, std::size_t Insert, std::size_t ...Left, std::size_t ...Right>
103-
struct insert<Pred, Insert, true, std::index_sequence<Left...>, Right...> {
104-
using type = std::index_sequence<Left..., Insert, Right...>;
120+
template <
121+
typename Pred,
122+
std::size_t l0,
123+
std::size_t ...l,
124+
std::size_t r0,
125+
std::size_t r1,
126+
std::size_t ...r>
127+
struct merge<
128+
Pred,
129+
true,
130+
std::index_sequence<l0, l...>,
131+
std::index_sequence<r0, r1, r...>
132+
> {
133+
using type = typename concat<
134+
std::index_sequence<r0>,
135+
typename merge<
136+
Pred,
137+
(bool)Pred::template apply<r1, l0>::value,
138+
std::index_sequence<l0, l...>,
139+
std::index_sequence<r1, r...>
140+
>::type
141+
>::type;
105142
};
106143

144+
template <
145+
typename Pred,
146+
std::size_t l0,
147+
std::size_t ...l,
148+
std::size_t r0>
149+
struct merge<
150+
Pred,
151+
true,
152+
std::index_sequence<l0, l...>,
153+
std::index_sequence<r0>
154+
> {
155+
using type = std::index_sequence<r0, l0, l...>;
156+
};
107157

108-
template <typename Pred, typename Result, std::size_t ...T>
109-
struct insertion_sort_impl;
158+
template <typename Pred, typename Left, typename Right>
159+
struct merge_helper;
110160

111-
template <typename Pred,
112-
std::size_t Result1, std::size_t ...Result,
113-
std::size_t T, std::size_t ...Ts>
114-
struct insertion_sort_impl<Pred, std::index_sequence<Result1, Result...>, T, Ts...> {
115-
using type = typename insertion_sort_impl<
161+
template <
162+
typename Pred,
163+
std::size_t l0,
164+
std::size_t ...l,
165+
std::size_t r0,
166+
std::size_t ...r>
167+
struct merge_helper<
168+
Pred,
169+
std::index_sequence<l0, l...>,
170+
std::index_sequence<r0, r...>
171+
> {
172+
using type = typename merge<
116173
Pred,
117-
typename insert<
118-
Pred, T, (bool)Pred::template apply<T, Result1>::value,
119-
std::index_sequence<>,
120-
Result1, Result...
121-
>::type,
122-
Ts...
174+
(bool)Pred::template apply<r0, l0>::value,
175+
std::index_sequence<l0, l...>,
176+
std::index_sequence<r0, r...>
123177
>::type;
124178
};
125179

126-
template <typename Pred, std::size_t T, std::size_t ...Ts>
127-
struct insertion_sort_impl<Pred, std::index_sequence<>, T, Ts...> {
128-
using type = typename insertion_sort_impl<
129-
Pred, std::index_sequence<T>, Ts...
130-
>::type;
180+
// split templated structure, Nr represents the number of elements
181+
// from Right to move to Left
182+
// There are two specializations:
183+
// The first handles the generic case (Nr > 0)
184+
// The second handles the stop condition (Nr == 0)
185+
// These two specializations are not strictly ordered as
186+
// the first cannot match Nr==0 && empty Right
187+
// the second cannot match Nr!=0
188+
// std::enable_if<Nr!=0> is therefore required to make sure these two
189+
// specializations will never both be candidates during an overload
190+
// resolution (otherwise ambiguity occurs for Nr==0 and non-empty Right)
191+
template <std::size_t Nr, typename Left, typename Right, typename=void>
192+
struct split;
193+
194+
template <
195+
std::size_t Nr,
196+
std::size_t ...l,
197+
std::size_t ...r,
198+
std::size_t r0>
199+
struct split<
200+
Nr,
201+
std::index_sequence<l...>,
202+
std::index_sequence<r0, r...>,
203+
typename std::enable_if<Nr!=0>::type
204+
> {
205+
using sp = split<
206+
Nr-1,
207+
std::index_sequence<l..., r0>,
208+
std::index_sequence<r...>
209+
>;
210+
using left = typename sp::left;
211+
using right = typename sp::right;
131212
};
132213

133-
template <typename Pred, typename Result>
134-
struct insertion_sort_impl<Pred, Result> {
135-
using type = Result;
214+
template <std::size_t ...l, std::size_t ...r>
215+
struct split<0, std::index_sequence<l...>, std::index_sequence<r...>> {
216+
using left = std::index_sequence<l...>;
217+
using right = std::index_sequence<r...>;
136218
};
137219

138-
template <typename Pred, typename Indices>
139-
struct sort_helper;
220+
template <typename Pred, typename Sequence>
221+
struct merge_sort_impl;
140222

141-
template <typename Pred, std::size_t ...i>
142-
struct sort_helper<Pred, std::index_sequence<i...>> {
143-
using type = typename insertion_sort_impl<
144-
Pred, std::index_sequence<>, i...
223+
template <typename Pred, std::size_t ...seq>
224+
struct merge_sort_impl<Pred, std::index_sequence<seq...>> {
225+
using sequence = std::index_sequence<seq...>;
226+
using sp = split<
227+
sequence::size() / 2,
228+
std::index_sequence<>,
229+
sequence
230+
>;
231+
using type = typename merge_helper<
232+
Pred,
233+
typename merge_sort_impl<Pred, typename sp::left>::type,
234+
typename merge_sort_impl<Pred, typename sp::right>::type
145235
>::type;
146236
};
237+
238+
template <typename Pred, std::size_t x>
239+
struct merge_sort_impl<Pred, std::index_sequence<x>> {
240+
using type = std::index_sequence<x>;
241+
};
242+
243+
template <typename Pred>
244+
struct merge_sort_impl<Pred, std::index_sequence<>> {
245+
using type = std::index_sequence<>;
246+
};
147247
} // end namespace detail
148248

149249
template <typename S, bool condition>
@@ -156,7 +256,7 @@ BOOST_HANA_NAMESPACE_BEGIN
156256
template <typename Xs, typename Pred>
157257
static constexpr auto apply(Xs&& xs, Pred const&) {
158258
constexpr std::size_t Len = decltype(hana::length(xs))::value;
159-
using Indices = typename detail::sort_helper<
259+
using Indices = typename detail::merge_sort_impl<
160260
detail::sort_predicate<Xs&&, Pred>,
161261
std::make_index_sequence<Len>
162262
>::type;

0 commit comments

Comments
 (0)