🛠️🐜 Antkeeper superbuild with dependencies included https://antkeeper.com
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

137 lines
5.0 KiB

  1. #ifndef ENTT_CORE_ALGORITHM_HPP
  2. #define ENTT_CORE_ALGORITHM_HPP
  3. #include <algorithm>
  4. #include <functional>
  5. #include <iterator>
  6. #include <utility>
  7. #include <vector>
  8. #include "utility.hpp"
  9. namespace entt {
  10. /**
  11. * @brief Function object to wrap `std::sort` in a class type.
  12. *
  13. * Unfortunately, `std::sort` cannot be passed as template argument to a class
  14. * template or a function template.<br/>
  15. * This class fills the gap by wrapping some flavors of `std::sort` in a
  16. * function object.
  17. */
  18. struct std_sort {
  19. /**
  20. * @brief Sorts the elements in a range.
  21. *
  22. * Sorts the elements in a range using the given binary comparison function.
  23. *
  24. * @tparam It Type of random access iterator.
  25. * @tparam Compare Type of comparison function object.
  26. * @tparam Args Types of arguments to forward to the sort function.
  27. * @param first An iterator to the first element of the range to sort.
  28. * @param last An iterator past the last element of the range to sort.
  29. * @param compare A valid comparison function object.
  30. * @param args Arguments to forward to the sort function, if any.
  31. */
  32. template<typename It, typename Compare = std::less<>, typename... Args>
  33. void operator()(It first, It last, Compare compare = Compare{}, Args &&...args) const {
  34. std::sort(std::forward<Args>(args)..., std::move(first), std::move(last), std::move(compare));
  35. }
  36. };
  37. /*! @brief Function object for performing insertion sort. */
  38. struct insertion_sort {
  39. /**
  40. * @brief Sorts the elements in a range.
  41. *
  42. * Sorts the elements in a range using the given binary comparison function.
  43. *
  44. * @tparam It Type of random access iterator.
  45. * @tparam Compare Type of comparison function object.
  46. * @param first An iterator to the first element of the range to sort.
  47. * @param last An iterator past the last element of the range to sort.
  48. * @param compare A valid comparison function object.
  49. */
  50. template<typename It, typename Compare = std::less<>>
  51. void operator()(It first, It last, Compare compare = Compare{}) const {
  52. if(first < last) {
  53. for(auto it = first + 1; it < last; ++it) {
  54. auto value = std::move(*it);
  55. auto pre = it;
  56. for(; pre > first && compare(value, *(pre - 1)); --pre) {
  57. *pre = std::move(*(pre - 1));
  58. }
  59. *pre = std::move(value);
  60. }
  61. }
  62. }
  63. };
  64. /**
  65. * @brief Function object for performing LSD radix sort.
  66. * @tparam Bit Number of bits processed per pass.
  67. * @tparam N Maximum number of bits to sort.
  68. */
  69. template<std::size_t Bit, std::size_t N>
  70. struct radix_sort {
  71. static_assert((N % Bit) == 0, "The maximum number of bits to sort must be a multiple of the number of bits processed per pass");
  72. /**
  73. * @brief Sorts the elements in a range.
  74. *
  75. * Sorts the elements in a range using the given _getter_ to access the
  76. * actual data to be sorted.
  77. *
  78. * This implementation is inspired by the online book
  79. * [Physically Based Rendering](http://www.pbr-book.org/3ed-2018/Primitives_and_Intersection_Acceleration/Bounding_Volume_Hierarchies.html#RadixSort).
  80. *
  81. * @tparam It Type of random access iterator.
  82. * @tparam Getter Type of _getter_ function object.
  83. * @param first An iterator to the first element of the range to sort.
  84. * @param last An iterator past the last element of the range to sort.
  85. * @param getter A valid _getter_ function object.
  86. */
  87. template<typename It, typename Getter = identity>
  88. void operator()(It first, It last, Getter getter = Getter{}) const {
  89. if(first < last) {
  90. static constexpr auto mask = (1 << Bit) - 1;
  91. static constexpr auto buckets = 1 << Bit;
  92. static constexpr auto passes = N / Bit;
  93. using value_type = typename std::iterator_traits<It>::value_type;
  94. std::vector<value_type> aux(std::distance(first, last));
  95. auto part = [getter = std::move(getter)](auto from, auto to, auto out, auto start) {
  96. std::size_t index[buckets]{};
  97. std::size_t count[buckets]{};
  98. for(auto it = from; it != to; ++it) {
  99. ++count[(getter(*it) >> start) & mask];
  100. }
  101. for(std::size_t pos{}, end = buckets - 1u; pos < end; ++pos) {
  102. index[pos + 1u] = index[pos] + count[pos];
  103. }
  104. for(auto it = from; it != to; ++it) {
  105. out[index[(getter(*it) >> start) & mask]++] = std::move(*it);
  106. }
  107. };
  108. for(std::size_t pass = 0; pass < (passes & ~1); pass += 2) {
  109. part(first, last, aux.begin(), pass * Bit);
  110. part(aux.begin(), aux.end(), first, (pass + 1) * Bit);
  111. }
  112. if constexpr(passes & 1) {
  113. part(first, last, aux.begin(), (passes - 1) * Bit);
  114. std::move(aux.begin(), aux.end(), first);
  115. }
  116. }
  117. }
  118. };
  119. } // namespace entt
  120. #endif