26struct __unsigned_projection
 
   31  template <std::
signed_
integral T>
 
   32  constexpr std::make_unsigned_t<T> operator()(T e) 
const noexcept 
   34    using uT = std::make_unsigned_t<T>;
 
   37    static_assert(
static_cast<uT
>(std::numeric_limits<T>::min())
 
   38                      + 
static_cast<uT
>(std::numeric_limits<T>::max())
 
   39                  == 
static_cast<uT
>(T(-1)));
 
   40    static_assert(std::numeric_limits<uT>::digits
 
   41                  == std::numeric_limits<T>::digits + 1);
 
   42    static_assert(std::bit_cast<uT>(std::numeric_limits<T>::min())
 
   43                  == (uT(1) << (
sizeof(T) * 8 - 1)));
 
   45    return std::bit_cast<uT>(std::forward<T>(e))
 
   46           ^ (uT(1) << (
sizeof(T) * 8 - 1));
 
   79  template <std::ranges::random_access_range R, 
typename P = std::identity,
 
   80            std::make_unsigned_t<std::remove_cvref_t<
 
   81                std::invoke_result_t<P, std::iter_value_t<R>>>>
 
   84    requires std::integral<
decltype(BITS)>
 
   85  constexpr void operator()(R&& range, P proj = {}) 
const 
   88    using T = std::iter_value_t<R>;
 
   91    using I = std::remove_cvref_t<std::invoke_result_t<P, T>>;
 
   92    using uI = std::make_unsigned_t<I>;
 
   94    if constexpr (!std::is_same_v<uI, I>)
 
   96      __radix_sort()(std::forward<R>(range), [&](
const T& e) -> uI
 
  101    if (range.size() <= 1)
 
  104    uI max_value = proj(*std::ranges::max_element(range, std::less{}, proj));
 
  107    constexpr uI bucket_size = 1 << BITS;
 
  108    uI mask = (uI(1) << BITS) - 1;
 
  116    bool all_first_bit = std::ranges::all_of(
 
  117        range, [&](
const auto& e)
 
  118        { 
return proj(e) & (uI(1) << (
sizeof(uI) * 8 - 1)); });
 
  120      max_value = max_value & ~(uI(1) << (
sizeof(uI) * 8 - 1));
 
  129    std::array<I, bucket_size> counter;
 
  130    std::array<I, bucket_size + 1> offset;
 
  133    std::vector<T> buffer(range.size());
 
  134    std::span<T> current_perm = range;
 
  135    std::span<T> next_perm = buffer;
 
  136    for (I i = 0; i < its; i++)
 
  139      std::ranges::fill(counter, 0);
 
  142      for (
const auto& c : current_perm)
 
  143        counter[(proj(c) & mask) >> mask_offset]++;
 
  147      std::partial_sum(counter.begin(), counter.end(),
 
  148                       std::next(offset.begin()));
 
  149      for (
const auto& c : current_perm)
 
  151        uI bucket = (proj(c) & mask) >> mask_offset;
 
  152        uI new_pos = offset[bucket + 1] - counter[bucket];
 
  153        next_perm[new_pos] = c;
 
  160      std::swap(current_perm, next_perm);
 
  165      std::ranges::copy(buffer, range.begin());
 
  182template <
typename T, 
int BITS = 16>
 
  183std::vector<std::int32_t> 
sort_by_perm(std::span<const T> x, std::size_t shape1)
 
  185  static_assert(std::is_integral_v<T>, 
"Integral required.");
 
  188    return std::vector<std::int32_t>{};
 
  191  assert(x.size() % shape1 == 0);
 
  192  const std::size_t shape0 = x.size() / shape1;
 
  193  std::vector<std::int32_t> perm(shape0);
 
  194  std::iota(perm.begin(), perm.end(), 0);
 
  198  std::vector<T> column(shape0);
 
  199  for (std::size_t i = 0; i < shape1; ++i)
 
  201    std::size_t col = shape1 - 1 - i;
 
  202    for (std::size_t j = 0; j < shape0; ++j)
 
  203      column[j] = x[j * shape1 + col];
 
  205    radix_sort(perm, [&column](
auto index) { 
return column[index]; });
 
 
Top-level namespace.
Definition defines.h:12
 
constexpr __unsigned_projection unsigned_projection
Projection from signed to signed int.
Definition sort.h:51
 
std::vector< std::int32_t > sort_by_perm(std::span< const T > x, std::size_t shape1)
Compute the permutation array that sorts a 2D array by row.
Definition sort.h:183
 
constexpr __radix_sort radix_sort
Radix sort.
Definition sort.h:170