fork download
  1. #include <algorithm> // iter_swap
  2. #include <type_traits> // integral_constant / false_type / true_type
  3. #include <iostream>
  4. #include <array>
  5. #include <chrono>
  6.  
  7. namespace Arcoth
  8. {
  9. template <typename I>
  10. void compare_swap( I& a, I& b )
  11. {
  12. if (a > b)
  13. std::swap(a, b);
  14. }
  15.  
  16. template <std::size_t lo, std::size_t hi, std::size_t r>
  17. struct oddeven_merge
  18. {
  19. template <typename Iter>
  20. void operator()(Iter first)
  21. {
  22. call_(first, std::integral_constant<bool, step < hi - lo>{});
  23. }
  24.  
  25. private:
  26. static auto const step = 2*r;
  27.  
  28. template <typename Iter>
  29. static void call_(Iter first, std::true_type)
  30. {
  31. oddeven_merge<lo , hi, step>{}(first);
  32. oddeven_merge<lo + r, hi, step>{}(first);
  33.  
  34. for (std::size_t i = lo + r; i <= hi - r; i += step)
  35. compare_swap(first[i], first[i+r]);
  36. }
  37.  
  38. template <typename Iter>
  39. static void call_(Iter first, std::false_type)
  40. {
  41. compare_swap(first[lo], first[lo+r]);
  42. }
  43. };
  44.  
  45. template <std::size_t lo, std::size_t hi>
  46. struct oddeven_merge_sort_range
  47. {
  48. static auto const mid = lo + (hi-lo)/2;
  49.  
  50. template <typename Iter>
  51. void operator()( Iter first )
  52. {
  53. oddeven_merge_sort_range<lo , mid>{}(first);
  54. oddeven_merge_sort_range<mid+1, hi >{}(first);
  55. oddeven_merge<lo, hi, 1>{}(first);
  56. }
  57. };
  58.  
  59. template <std::size_t lo>
  60. struct oddeven_merge_sort_range<lo, lo>
  61. {
  62. template <typename I> void operator()(I) {}
  63. };
  64.  
  65. template <std::size_t N, typename Iter>
  66. void oddeven_merge_sort( Iter i )
  67. {
  68. static_assert( (N & (N-1)) == 0 && N != 0, "N must be a power of 2" );
  69. oddeven_merge_sort_range<0, N-1>{}(i);
  70. }
  71. }
  72.  
  73. namespace camper
  74. {
  75. template <typename T>
  76. using eval = typename T::type;
  77.  
  78. template <typename T> struct identity
  79. {
  80. using type = T;
  81. };
  82.  
  83. template <int... i> struct index_list : identity<index_list<i...>> {};
  84.  
  85. template <int N, int... i> struct make_index_list : make_index_list<N-1, 0, 1+i...> {};
  86.  
  87. template <int... i> struct make_index_list<0, i...> : index_list<i...> {};
  88.  
  89. template <typename... T> struct type_list : identity<type_list<T...>> {};
  90.  
  91. template <typename... T> struct merge_type_lists : merge_type_lists<eval<T>...> {};
  92. template <typename... T, typename... U, typename... V>
  93. struct merge_type_lists<type_list<T...>, type_list<U...>, V...>
  94. : merge_type_lists<type_list<T..., U...>, V...>
  95. {};
  96. template <typename... T>
  97. struct merge_type_lists<type_list<T...>>
  98. : type_list<T...>
  99. {};
  100.  
  101. /////////////////////////////////////
  102. template <int a, int b>
  103. struct index_pair
  104. {
  105. static constexpr auto first = a;
  106. static constexpr auto second = b;
  107. };
  108.  
  109. template <int lo, int hi, int r, typename = eval<make_index_list<(hi-lo)/(2*r)>>>
  110. struct oddeven_merge_simple_range;
  111. template <int lo, int hi, int r, int... I>
  112. struct oddeven_merge_simple_range<lo, hi, r, index_list<I...>>
  113. : type_list<index_pair<lo+r+I*2*r,lo+2*r+I*2*r>...>
  114. {};
  115.  
  116. template <int lo, int hi, int r>
  117. struct oddeven_merge
  118. : std::conditional<(r*2<hi-lo),
  119. merge_type_lists<oddeven_merge<lo, hi, 2*r>, oddeven_merge<lo+r, hi, 2*r>, oddeven_merge_simple_range<lo, hi, r>>,
  120. type_list<index_pair<lo, lo+r>>>::type
  121. {};
  122.  
  123. template <int lo, int hi>
  124. struct oddeven_merge_sort_range
  125. : std::conditional<(lo<hi),
  126. merge_type_lists<oddeven_merge_sort_range<lo, lo+(hi-lo)/2>, oddeven_merge_sort_range<lo+(hi-lo)/2+1,hi>, oddeven_merge<lo,hi,1>>,
  127. type_list<>>::type
  128. {};
  129.  
  130. struct evaluator
  131. {
  132. template <typename... Args>
  133. evaluator(Args&&...) {}
  134. };
  135. void evaluate(evaluator) {}
  136.  
  137. template <typename RandomIter, typename... Pairs>
  138. void oddeven_merge_sort_loop(RandomIter begin, type_list<Pairs...>)
  139. {
  140. static constexpr unsigned char pairs[][2] = { { Pairs::first, Pairs::second }... };
  141. for ( int i = 0; i != sizeof...(Pairs); ++i )
  142. Arcoth::compare_swap( begin[pairs[i][0]], begin[pairs[i][1]] );
  143. }
  144.  
  145. template <std::size_t N, typename RandomIter>
  146. void oddeven_merge_sort_loop(RandomIter begin)
  147. {
  148. static_assert( N>0 && (N&(N-1))==0, "N must be power of 2" );
  149. oddeven_merge_sort_loop(begin, eval<oddeven_merge_sort_range<0, N-1>>{});
  150. }
  151. template <typename RandomIter, typename... Pairs>
  152. void oddeven_merge_sort_unrolled(RandomIter begin, type_list<Pairs...>)
  153. {
  154. bool x[]={ ((begin[Pairs::second]<begin[Pairs::first]?std::swap(begin[Pairs::second],begin[Pairs::first]):void()),false)... };(void)x;
  155. }
  156.  
  157. template <std::size_t N, typename RandomIter>
  158. void oddeven_merge_sort_unrolled(RandomIter begin)
  159. {
  160. static_assert( N>0 && (N&(N-1))==0, "N must be power of 2" );
  161. oddeven_merge_sort_unrolled(begin, eval<oddeven_merge_sort_range<0, N-1>>{});
  162. }
  163.  
  164.  
  165. }
  166.  
  167. namespace SeppJ
  168. {
  169. template <std::size_t N, std::size_t step_size, std::size_t step = 1> struct odd_even_compare
  170. {
  171. template<typename Iterator> void operator() (Iterator it)
  172. {
  173. if (it[step * step_size + step_size] < it[step * step_size])
  174. std::swap(it[step * step_size + step_size], it[step * step_size]);
  175. odd_even_compare<N, step_size, step + 1>()(it);
  176. }
  177. };
  178.  
  179. template <std::size_t N, std::size_t step_size> struct odd_even_compare<N, step_size, N>
  180. {
  181. template<typename Iterator> void operator() (Iterator it)
  182. {
  183. if (it[N * step_size + step_size] < it[N * step_size])
  184. std::swap(it[N * step_size + step_size], it[N * step_size]);
  185. }
  186. };
  187.  
  188.  
  189. template <std::size_t N, std::size_t step_size = 1> struct odd_even_merge
  190. {
  191. template<typename Iterator> void operator()(Iterator it)
  192. {
  193. odd_even_merge<N/2, 2 * step_size>()(it);
  194. odd_even_merge<N/2, 2 * step_size>()(it + step_size);
  195. odd_even_compare<N - 3, step_size>()(it);
  196. }
  197. };
  198.  
  199. template<std::size_t step_size> struct odd_even_merge<2, step_size>
  200. {
  201. template<typename Iterator> void operator()(Iterator it)
  202. {
  203. if (it[step_size] < it[0])
  204. std::swap(it[0], it[step_size]);
  205. }
  206. };
  207.  
  208. template <std::size_t N> struct odd_even_mergesort
  209. {
  210. template<typename Iterator> void operator()(Iterator it)
  211. {
  212. odd_even_mergesort<N/2>()(it);
  213. odd_even_mergesort<N/2>()(it + N/2);
  214. odd_even_merge<N>()(it);
  215. }
  216. };
  217.  
  218. template<> struct odd_even_mergesort<1>
  219. {template<typename Iterator> void operator() (Iterator) {}};
  220.  
  221. template<> struct odd_even_mergesort<0>
  222. {template<typename Iterator> void operator() (Iterator) {}};
  223. }
  224.  
  225. #include <array>
  226. #include <random>
  227. #include <memory>
  228.  
  229. template <std::size_t N,
  230. std::size_t outer_loopings,
  231. std::size_t inner_loopings,
  232. typename T>
  233. void test(T obj, int64_t const* values)
  234. {
  235. using namespace std::chrono;
  236. auto best = high_resolution_clock::duration::max();
  237.  
  238. uint64_t check;
  239.  
  240. uint64_t array[N*inner_loopings];
  241.  
  242. for (unsigned j = 0; j != outer_loopings; ++j )
  243. {
  244. check = 0;
  245.  
  246. std::copy_n( values, N*inner_loopings, array );
  247.  
  248. auto start = high_resolution_clock::now();
  249.  
  250. for (unsigned i = 0; i != inner_loopings; ++i)
  251. {
  252. obj( array + N*i );
  253.  
  254. for (std::size_t c = 0; c != N; c += 2)
  255. (check += array[c]) *= array[c+1];
  256. }
  257.  
  258. auto end = high_resolution_clock::now();
  259.  
  260. if (end - start < best)
  261. {
  262. best = end - start;
  263. j = 0;
  264. }
  265. }
  266.  
  267. std::cout << best.count() << ' ' << std::hex << check << std::dec << '\n';
  268. }
  269.  
  270. auto constexpr size = 64, inner = 2048, outer = 5000;
  271.  
  272. int main()
  273. {
  274. std::uniform_int_distribution<int64_t> dis(std::numeric_limits<int64_t>::min());
  275. std::mt19937_64 engine( std::random_device{}() );
  276.  
  277. int64_t values[size*inner];
  278.  
  279. std::generate( std::begin(values), std::end(values), [&] {return dis(engine);} );
  280.  
  281. std::cout << "SeppJ: "; test<size, outer, inner>( SeppJ::odd_even_mergesort<size>{} , values );
  282. std::cout << "camper(Loop): "; test<size, outer, inner>( [] (auto iter) {camper::oddeven_merge_sort_loop<size>(iter);}, values );
  283. std::cout << "camper(unrolled): "; test<size, outer, inner>( [] (auto iter) {camper::oddeven_merge_sort_unrolled<size>(iter);}, values );
  284. std::cout << "Arcoth: "; test<size, outer, inner>( [] (auto iter) {Arcoth::oddeven_merge_sort<size>(iter);}, values );
  285. }
  286.  
Compilation error #stdin compilation error #stdout 0s 0KB
stdin
Standard input is empty
compilation info
prog.cpp: In function ‘int main()’:
prog.cpp:282:72: error: parameter declared ‘auto’
  std::cout << "camper(Loop):     "; test<size, outer, inner>( [] (auto iter) {camper::oddeven_merge_sort_loop<size>(iter);}, values );
                                                                        ^
prog.cpp: In lambda function:
prog.cpp:282:117: error: ‘iter’ was not declared in this scope
  std::cout << "camper(Loop):     "; test<size, outer, inner>( [] (auto iter) {camper::oddeven_merge_sort_loop<size>(iter);}, values );
                                                                                                                     ^
prog.cpp: In function ‘int main()’:
prog.cpp:283:72: error: parameter declared ‘auto’
  std::cout << "camper(unrolled): "; test<size, outer, inner>( [] (auto iter) {camper::oddeven_merge_sort_unrolled<size>(iter);}, values );
                                                                        ^
prog.cpp: In lambda function:
prog.cpp:283:121: error: ‘iter’ was not declared in this scope
  std::cout << "camper(unrolled): "; test<size, outer, inner>( [] (auto iter) {camper::oddeven_merge_sort_unrolled<size>(iter);}, values );
                                                                                                                         ^
prog.cpp: In function ‘int main()’:
prog.cpp:284:72: error: parameter declared ‘auto’
  std::cout << "Arcoth:           "; test<size, outer, inner>( [] (auto iter) {Arcoth::oddeven_merge_sort<size>(iter);}, values );
                                                                        ^
prog.cpp: In lambda function:
prog.cpp:284:112: error: ‘iter’ was not declared in this scope
  std::cout << "Arcoth:           "; test<size, outer, inner>( [] (auto iter) {Arcoth::oddeven_merge_sort<size>(iter);}, values );
                                                                                                                ^
prog.cpp: In instantiation of ‘void test(T, const int64_t*) [with unsigned int N = 64u; unsigned int outer_loopings = 5000u; unsigned int inner_loopings = 2048u; T = main()::__lambda1; int64_t = long long int]’:
prog.cpp:282:133:   required from here
prog.cpp:252:22: error: no match for call to ‘(main()::__lambda1) (uint64_t*)’
     obj( array + N*i );
                      ^
prog.cpp:282:64: note: candidates are:
  std::cout << "camper(Loop):     "; test<size, outer, inner>( [] (auto iter) {camper::oddeven_merge_sort_loop<size>(iter);}, values );
                                                                ^
prog.cpp:252:22: note: void (*)() <conversion>
     obj( array + N*i );
                      ^
prog.cpp:252:22: note:   candidate expects 1 argument, 2 provided
prog.cpp:282:76: note: main()::__lambda1
  std::cout << "camper(Loop):     "; test<size, outer, inner>( [] (auto iter) {camper::oddeven_merge_sort_loop<size>(iter);}, values );
                                                                            ^
prog.cpp:282:76: note:   candidate expects 0 arguments, 1 provided
prog.cpp: In instantiation of ‘void test(T, const int64_t*) [with unsigned int N = 64u; unsigned int outer_loopings = 5000u; unsigned int inner_loopings = 2048u; T = main()::__lambda2; int64_t = long long int]’:
prog.cpp:283:137:   required from here
prog.cpp:252:22: error: no match for call to ‘(main()::__lambda2) (uint64_t*)’
     obj( array + N*i );
                      ^
prog.cpp:283:64: note: candidates are:
  std::cout << "camper(unrolled): "; test<size, outer, inner>( [] (auto iter) {camper::oddeven_merge_sort_unrolled<size>(iter);}, values );
                                                                ^
prog.cpp:252:22: note: void (*)() <conversion>
     obj( array + N*i );
                      ^
prog.cpp:252:22: note:   candidate expects 1 argument, 2 provided
prog.cpp:283:76: note: main()::__lambda2
  std::cout << "camper(unrolled): "; test<size, outer, inner>( [] (auto iter) {camper::oddeven_merge_sort_unrolled<size>(iter);}, values );
                                                                            ^
prog.cpp:283:76: note:   candidate expects 0 arguments, 1 provided
prog.cpp: In instantiation of ‘void test(T, const int64_t*) [with unsigned int N = 64u; unsigned int outer_loopings = 5000u; unsigned int inner_loopings = 2048u; T = main()::__lambda3; int64_t = long long int]’:
prog.cpp:284:128:   required from here
prog.cpp:252:22: error: no match for call to ‘(main()::__lambda3) (uint64_t*)’
     obj( array + N*i );
                      ^
prog.cpp:284:64: note: candidates are:
  std::cout << "Arcoth:           "; test<size, outer, inner>( [] (auto iter) {Arcoth::oddeven_merge_sort<size>(iter);}, values );
                                                                ^
prog.cpp:252:22: note: void (*)() <conversion>
     obj( array + N*i );
                      ^
prog.cpp:252:22: note:   candidate expects 1 argument, 2 provided
prog.cpp:284:76: note: main()::__lambda3
  std::cout << "Arcoth:           "; test<size, outer, inner>( [] (auto iter) {Arcoth::oddeven_merge_sort<size>(iter);}, values );
                                                                            ^
prog.cpp:284:76: note:   candidate expects 0 arguments, 1 provided
stdout
Standard output is empty