compilesort.hpp 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. /**
  2. * Implementation of compile-time sort for symbol table entries.
  3. */
  4. #pragma once
  5. #ifdef __cplusplus
  6. #include <iterator>
  7. #include <array>
  8. namespace cstd {
  9. template <typename RAIt>
  10. constexpr RAIt next(RAIt it, typename std::iterator_traits<RAIt>::difference_type n = 1) {
  11. return it + n;
  12. }
  13. template <typename RAIt>
  14. constexpr auto distance(RAIt first, RAIt last) {
  15. return last - first;
  16. }
  17. template <class ForwardIt1, class ForwardIt2>
  18. constexpr void iter_swap(ForwardIt1 a, ForwardIt2 b) {
  19. auto temp = std::move(*a);
  20. *a = std::move(*b);
  21. *b = std::move(temp);
  22. }
  23. template <class InputIt, class UnaryPredicate>
  24. constexpr InputIt find_if_not(InputIt first, InputIt last, UnaryPredicate q) {
  25. for(; first != last; ++first) {
  26. if(!q(*first)) {
  27. return first;
  28. }
  29. }
  30. return last;
  31. }
  32. template <class ForwardIt, class UnaryPredicate>
  33. constexpr ForwardIt partition(ForwardIt first, ForwardIt last, UnaryPredicate p) {
  34. first = cstd::find_if_not(first, last, p);
  35. if(first == last) return first;
  36. for(ForwardIt i = cstd::next(first); i != last; ++i) {
  37. if(p(*i)) {
  38. cstd::iter_swap(i, first);
  39. ++first;
  40. }
  41. }
  42. return first;
  43. }
  44. }
  45. template <class RAIt, class Compare = std::less<> >
  46. constexpr void quick_sort(RAIt first, RAIt last, Compare cmp = Compare{}) {
  47. auto const N = cstd::distance(first, last);
  48. if(N <= 1) return;
  49. auto const pivot = *cstd::next(first, N / 2);
  50. auto const middle1 =
  51. cstd::partition(first, last, [=](auto const& elem) { return cmp(elem, pivot); });
  52. auto const middle2 =
  53. cstd::partition(middle1, last, [=](auto const& elem) { return !cmp(pivot, elem); });
  54. quick_sort(first, middle1, cmp); // assert(std::is_sorted(first, middle1, cmp));
  55. quick_sort(middle2, last, cmp); // assert(std::is_sorted(middle2, last, cmp));
  56. }
  57. template <typename Range>
  58. constexpr auto sort(Range&& range) {
  59. quick_sort(std::begin(range), std::end(range));
  60. return range;
  61. }
  62. template <typename V, typename... T>
  63. constexpr auto array_of(T&&... t) -> std::array<V, sizeof...(T)> {
  64. return {{std::forward<T>(t)...}};
  65. }
  66. template <typename T, typename... N>
  67. constexpr auto my_make_array(N&&... args) -> std::array<T, sizeof...(args)> {
  68. return {std::forward<N>(args)...};
  69. }
  70. namespace traits {
  71. template <typename T, typename... Ts>
  72. struct array_type {
  73. using type = T;
  74. };
  75. template <typename T, typename... Ts>
  76. static constexpr bool are_same_type() {
  77. return std::conjunction_v<std::is_same<T, Ts>...>;
  78. }
  79. }
  80. template <typename... T>
  81. constexpr auto create_array(const T&&... values) {
  82. using array_type = typename traits::array_type<T...>::type;
  83. static_assert(sizeof...(T) > 0, "an array must have at least one element");
  84. static_assert(traits::are_same_type<T...>(), "all elements must have same type");
  85. return std::array<array_type, sizeof...(T)>{values...};
  86. }
  87. template <typename T, typename... Ts>
  88. constexpr auto create_array_t(const Ts&&... values) {
  89. using array_type = T;
  90. static_assert(sizeof...(Ts) > 0, "an array must have at least one element");
  91. static_assert(traits::are_same_type<Ts...>(), "all elements must have same type");
  92. return std::array<array_type, sizeof...(Ts)>{static_cast<T>(values)...};
  93. }
  94. #endif