9 #ifndef EAGINE_SORTING_NETWORK_HPP
10 #define EAGINE_SORTING_NETWORK_HPP
15 #include <type_traits>
19 class bitonic_sorting_network_base {
21 static constexpr
auto _next_log(std::size_t n, std::size_t pot = 1) noexcept
23 return (n > pot) ? 1U + _next_log(n, pot << 1U) : 0U;
26 static constexpr
auto _hlp(std::size_t n) noexcept -> std::size_t {
27 return (n == 0) ? 0 : n + _hlp(n - 1);
30 template <std::
size_t N>
31 static void _fill_idx(std::array<std::size_t, N>* idx) noexcept {
33 for(std::size_t k = 0, l = _next_log(N); k < l; ++k) {
34 for(std::size_t m = 0; m <= k; ++m, ++r) {
35 std::size_t d = 1U << (k - m);
36 std::array<std::size_t, N>&
row = idx[r];
38 for(std::size_t i = 0; i < N; ++i) {
39 std::size_t inv = ((i >> k) & 2U) >> 1U;
40 std::size_t j = i + ((i & d) == 0 ? d : -d);
45 row[i] = (j << 1U) | inv;
52 static constexpr
auto num_rounds_for(
span_size_t n) noexcept
58 template <span_
size_t N>
59 class bitonic_sorting_network :
public bitonic_sorting_network_base {
61 using _base = bitonic_sorting_network_base;
63 std::array<std::array<std::size_t, N>, _base::num_rounds_for(N)>;
65 static auto _make_idx() {
67 _base::_fill_idx(result.data());
71 static auto _get_idx() -> _idx_t& {
72 static _idx_t idx = _make_idx();
81 static constexpr
auto size() noexcept ->
span_size_t {
85 static constexpr
auto rounds() noexcept ->
span_size_t {
86 return _base::num_rounds_for(N);
94 return (_c(r, i) & 1U) == 1U;
98 return inv(r, i) ? (i > j) : (i < j);
102 return inv(r, i) ? (i < j) : (i > j);
106 template <span_
size_t N>
107 struct manual_sorting_network_base {
108 static constexpr
bool is_specialized =
false;
111 template <span_
size_t N>
112 struct manual_sorting_network : manual_sorting_network_base<N> {
114 using _base = manual_sorting_network_base<N>;
117 static constexpr
auto size() noexcept ->
span_size_t {
121 static constexpr
auto
126 static constexpr
auto
133 struct manual_sorting_network_base<1> {
134 static constexpr
bool is_specialized =
true;
136 static constexpr
auto rounds() noexcept ->
span_size_t {
140 static constexpr
auto
147 struct manual_sorting_network_base<2> {
148 static constexpr
bool is_specialized =
true;
150 static constexpr
auto rounds() noexcept ->
span_size_t {
154 static constexpr
auto
156 return elem == 0 ? 1 : 0;
161 struct manual_sorting_network_base<3> {
162 static constexpr
bool is_specialized =
true;
164 static constexpr
auto rounds() noexcept ->
span_size_t {
168 static constexpr
span_size_t idx[3][3] = {{1, 0, 2}, {0, 2, 1}, {1, 0, 2}};
172 return idx[round][elem];
176 constexpr
span_size_t manual_sorting_network_base<3>::idx[3][3];
179 struct manual_sorting_network_base<4> {
180 static constexpr
bool is_specialized =
true;
182 static constexpr
auto size() noexcept ->
span_size_t {
186 static constexpr
auto rounds() noexcept ->
span_size_t {
197 return idx[round][elem];
201 constexpr
span_size_t manual_sorting_network_base<4>::idx[3][4];
204 struct manual_sorting_network_base<5> {
205 static constexpr
bool is_specialized =
true;
207 static constexpr
auto size() noexcept ->
span_size_t {
211 static constexpr
auto rounds() noexcept ->
span_size_t {
224 return idx[round][elem];
228 constexpr
span_size_t manual_sorting_network_base<5>::idx[5][5];
231 struct manual_sorting_network_base<6> {
232 static constexpr
bool is_specialized =
true;
234 static constexpr
auto size() noexcept ->
span_size_t {
238 static constexpr
auto rounds() noexcept ->
span_size_t {
251 return idx[round][elem];
255 constexpr
span_size_t manual_sorting_network_base<6>::idx[5][6];
258 struct manual_sorting_network_base<7> {
259 static constexpr
bool is_specialized =
true;
261 static constexpr
auto size() noexcept ->
span_size_t {
265 static constexpr
auto rounds() noexcept ->
span_size_t {
270 {1, 0, 3, 2, 5, 4, 6},
271 {2, 3, 0, 1, 6, 5, 4},
272 {4, 5, 6, 3, 0, 1, 2},
273 {0, 4, 2, 6, 1, 5, 3},
274 {0, 1, 4, 5, 2, 3, 6},
275 {0, 2, 1, 4, 3, 6, 5}};
279 return idx[round][elem];
283 constexpr
span_size_t manual_sorting_network_base<7>::idx[6][7];
286 struct manual_sorting_network_base<8> {
287 static constexpr
bool is_specialized =
true;
289 static constexpr
auto size() noexcept ->
span_size_t {
293 static constexpr
auto rounds() noexcept ->
span_size_t {
298 {1, 0, 3, 2, 5, 4, 7, 6},
299 {2, 3, 0, 1, 6, 7, 4, 5},
300 {4, 2, 1, 7, 0, 6, 5, 3},
301 {0, 5, 6, 3, 4, 1, 2, 7},
302 {0, 1, 4, 5, 2, 3, 6, 7},
303 {0, 2, 1, 4, 3, 6, 5, 7}};
307 return idx[round][elem];
311 constexpr
span_size_t manual_sorting_network_base<8>::idx[6][8];
314 struct manual_sorting_network_base<9> {
315 static constexpr
bool is_specialized =
true;
317 static constexpr
auto size() noexcept ->
span_size_t {
321 static constexpr
auto rounds() noexcept ->
span_size_t {
326 {7, 6, 5, 4, 3, 2, 1, 0, 8},
327 {3, 2, 1, 0, 7, 5, 8, 4, 6},
328 {1, 0, 6, 4, 3, 8, 2, 7, 5},
329 {0, 2, 1, 5, 6, 3, 4, 8, 7},
330 {0, 3, 4, 1, 2, 7, 6, 5, 8},
331 {1, 0, 3, 2, 5, 4, 7, 6, 8},
332 {0, 1, 2, 4, 3, 6, 5, 7, 8}};
336 return idx[round][elem];
340 constexpr
span_size_t manual_sorting_network_base<9>::idx[7][9];
343 struct manual_sorting_network_base<10> {
344 static constexpr
bool is_specialized =
true;
346 static constexpr
auto size() noexcept ->
span_size_t {
350 static constexpr
auto rounds() noexcept ->
span_size_t {
355 {1, 0, 3, 2, 5, 4, 7, 6, 9, 8},
356 {5, 8, 6, 7, 9, 0, 2, 3, 1, 4},
357 {2, 4, 0, 6, 1, 8, 3, 9, 5, 7},
358 {1, 0, 7, 5, 6, 3, 4, 2, 9, 8},
359 {0, 3, 4, 1, 2, 7, 8, 5, 6, 9},
360 {0, 2, 1, 4, 3, 6, 5, 8, 7, 9},
361 {0, 1, 3, 2, 5, 4, 7, 6, 8, 9},
366 return idx[round][elem];
370 constexpr
span_size_t manual_sorting_network_base<10>::idx[7][10];
373 struct manual_sorting_network_base<11> {
374 static constexpr
bool is_specialized =
true;
376 static constexpr
auto size() noexcept ->
span_size_t {
380 static constexpr
auto rounds() noexcept ->
span_size_t {
385 {0, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1},
386 {6, 4, 3, 2, 1, 5, 0, 10, 9, 8, 7},
387 {1, 0, 5, 4, 3, 2, 6, 8, 7, 10, 9},
388 {2, 5, 0, 3, 6, 1, 4, 7, 9, 8, 10},
389 {0, 8, 3, 2, 7, 9, 10, 4, 1, 5, 6},
390 {0, 4, 2, 5, 1, 3, 9, 8, 7, 6, 10},
391 {0, 2, 1, 4, 3, 7, 8, 5, 6, 9, 10},
392 {0, 1, 3, 2, 5, 4, 7, 6, 8, 9, 10},
397 return idx[round][elem];
401 constexpr
span_size_t manual_sorting_network_base<11>::idx[8][11];
404 struct manual_sorting_network_base<12> {
405 static constexpr
bool is_specialized =
true;
407 static constexpr
auto size() noexcept ->
span_size_t {
411 static constexpr
auto rounds() noexcept ->
span_size_t {
416 {6, 7, 8, 9, 10, 11, 0, 1, 2, 3, 4, 5},
417 {3, 4, 5, 0, 1, 2, 9, 10, 11, 6, 7, 8},
418 {1, 0, 2, 6, 5, 4, 3, 8, 7, 9, 11, 10},
419 {0, 2, 1, 4, 3, 8, 7, 6, 5, 10, 9, 11},
420 {1, 0, 9, 6, 5, 4, 3, 8, 7, 2, 11, 10},
421 {0, 3, 6, 1, 7, 9, 2, 4, 10, 5, 8, 11},
422 {0, 1, 3, 2, 6, 7, 4, 5, 9, 8, 10, 11},
423 {0, 1, 2, 4, 3, 6, 5, 8, 7, 9, 10, 11}};
427 return idx[round][elem];
431 constexpr
span_size_t manual_sorting_network_base<12>::idx[8][12];
434 struct manual_sorting_network_base<14> {
435 static constexpr
bool is_specialized =
true;
437 static constexpr
auto size() noexcept ->
span_size_t {
441 static constexpr
auto rounds() noexcept ->
span_size_t {
446 {13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0},
447 {5, 4, 3, 2, 1, 0, 6, 7, 13, 12, 11, 10, 9, 8},
448 {1, 0, 2, 6, 5, 4, 3, 10, 9, 8, 7, 11, 13, 12},
449 {0, 7, 8, 4, 3, 11, 12, 1, 2, 10, 9, 5, 6, 13},
450 {3, 2, 1, 0, 9, 8, 7, 6, 5, 4, 13, 12, 11, 10},
451 {1, 0, 3, 2, 8, 7, 9, 5, 4, 6, 11, 10, 13, 12},
452 {0, 2, 1, 5, 6, 3, 4, 9, 10, 7, 8, 12, 11, 13},
453 {0, 1, 2, 4, 3, 6, 5, 8, 7, 10, 9, 11, 12, 13},
454 {0, 1, 3, 2, 5, 4, 7, 6, 9, 8, 11, 10, 12, 13}};
458 return idx[round][elem];
462 constexpr
span_size_t manual_sorting_network_base<14>::idx[9][14];
465 struct manual_sorting_network_base<16> {
466 static constexpr
bool is_specialized =
true;
468 static constexpr
auto size() noexcept ->
span_size_t {
472 static constexpr
auto rounds() noexcept ->
span_size_t {
477 {15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0},
478 {7, 6, 5, 4, 3, 2, 1, 0, 15, 14, 13, 12, 11, 10, 9, 8},
479 {3, 2, 1, 0, 7, 6, 5, 4, 11, 10, 9, 8, 15, 14, 13, 12},
480 {1, 0, 8, 9, 5, 4, 12, 13, 2, 3, 11, 10, 6, 7, 15, 14},
481 {0, 4, 3, 2, 1, 10, 9, 8, 7, 6, 5, 14, 13, 12, 11, 15},
482 {0, 2, 1, 4, 3, 9, 8, 10, 6, 5, 7, 12, 11, 14, 13, 15},
483 {0, 1, 3, 2, 6, 7, 4, 5, 10, 11, 8, 9, 13, 12, 14, 15},
484 {0, 1, 2, 3, 5, 4, 7, 6, 9, 8, 11, 10, 12, 13, 14, 15},
485 {0, 1, 2, 4, 3, 6, 5, 8, 7, 11, 9, 12, 11, 13, 14, 15}};
489 return idx[round][elem];
493 constexpr
span_size_t manual_sorting_network_base<16>::idx[9][16];
495 template <span_
size_t N>
496 struct sorting_network
497 : std::conditional_t<
498 manual_sorting_network<N>::is_specialized,
499 manual_sorting_network<N>,
500 bitonic_sorting_network<N>> {};
504 #endif // EAGINE_SORTING_NETWORK_HPP