#ifndef ENTT_CORE_ALGORITHM_HPP #define ENTT_CORE_ALGORITHM_HPP #include #include #include #include #include #include "utility.hpp" namespace entt { /** * @brief Function object to wrap `std::sort` in a class type. * * Unfortunately, `std::sort` cannot be passed as template argument to a class * template or a function template.
* This class fills the gap by wrapping some flavors of `std::sort` in a * function object. */ struct std_sort { /** * @brief Sorts the elements in a range. * * Sorts the elements in a range using the given binary comparison function. * * @tparam It Type of random access iterator. * @tparam Compare Type of comparison function object. * @tparam Args Types of arguments to forward to the sort function. * @param first An iterator to the first element of the range to sort. * @param last An iterator past the last element of the range to sort. * @param compare A valid comparison function object. * @param args Arguments to forward to the sort function, if any. */ template, typename... Args> void operator()(It first, It last, Compare compare = Compare{}, Args &&...args) const { std::sort(std::forward(args)..., std::move(first), std::move(last), std::move(compare)); } }; /*! @brief Function object for performing insertion sort. */ struct insertion_sort { /** * @brief Sorts the elements in a range. * * Sorts the elements in a range using the given binary comparison function. * * @tparam It Type of random access iterator. * @tparam Compare Type of comparison function object. * @param first An iterator to the first element of the range to sort. * @param last An iterator past the last element of the range to sort. * @param compare A valid comparison function object. */ template> void operator()(It first, It last, Compare compare = Compare{}) const { if(first < last) { for(auto it = first + 1; it < last; ++it) { auto value = std::move(*it); auto pre = it; for(; pre > first && compare(value, *(pre - 1)); --pre) { *pre = std::move(*(pre - 1)); } *pre = std::move(value); } } } }; /** * @brief Function object for performing LSD radix sort. * @tparam Bit Number of bits processed per pass. * @tparam N Maximum number of bits to sort. */ template struct radix_sort { static_assert((N % Bit) == 0, "The maximum number of bits to sort must be a multiple of the number of bits processed per pass"); /** * @brief Sorts the elements in a range. * * Sorts the elements in a range using the given _getter_ to access the * actual data to be sorted. * * This implementation is inspired by the online book * [Physically Based Rendering](http://www.pbr-book.org/3ed-2018/Primitives_and_Intersection_Acceleration/Bounding_Volume_Hierarchies.html#RadixSort). * * @tparam It Type of random access iterator. * @tparam Getter Type of _getter_ function object. * @param first An iterator to the first element of the range to sort. * @param last An iterator past the last element of the range to sort. * @param getter A valid _getter_ function object. */ template void operator()(It first, It last, Getter getter = Getter{}) const { if(first < last) { static constexpr auto mask = (1 << Bit) - 1; static constexpr auto buckets = 1 << Bit; static constexpr auto passes = N / Bit; using value_type = typename std::iterator_traits::value_type; std::vector aux(std::distance(first, last)); auto part = [getter = std::move(getter)](auto from, auto to, auto out, auto start) { std::size_t index[buckets]{}; std::size_t count[buckets]{}; for(auto it = from; it != to; ++it) { ++count[(getter(*it) >> start) & mask]; } for(std::size_t pos{}, end = buckets - 1u; pos < end; ++pos) { index[pos + 1u] = index[pos] + count[pos]; } for(auto it = from; it != to; ++it) { out[index[(getter(*it) >> start) & mask]++] = std::move(*it); } }; for(std::size_t pass = 0; pass < (passes & ~1); pass += 2) { part(first, last, aux.begin(), pass * Bit); part(aux.begin(), aux.end(), first, (pass + 1) * Bit); } if constexpr(passes & 1) { part(first, last, aux.begin(), (passes - 1) * Bit); std::move(aux.begin(), aux.end(), first); } } } }; } // namespace entt #endif