PhysicsBasedAnimationToolkit 0.0.10
Cross-platform C++20 library of algorithms and data structures commonly used in computer graphics research on physically-based simulation.
Loading...
Searching...
No Matches
CountingSort.h
Go to the documentation of this file.
1
10
11#ifndef PBAT_COMMON_COUNTINGSORT_H
12#define PBAT_COMMON_COUNTINGSORT_H
13
14#include <algorithm>
15#include <concepts>
16#include <iterator>
17#include <limits>
18#include <numeric>
19#include <type_traits>
20
21namespace pbat::common {
22
40template <
41 std::random_access_iterator TWorkBegin,
42 std::random_access_iterator TWorkEnd,
43 std::random_access_iterator TValuesBegin,
44 std::random_access_iterator TValuesEnd,
45 class FKey,
46 class T = typename std::iterator_traits<TValuesBegin>::value_type,
47 class TKey = typename std::invoke_result_t<FKey, T>>
49 TWorkBegin wb,
50 TWorkEnd we,
51 TValuesBegin vb,
52 TValuesEnd ve,
53 TKey keyMin = std::numeric_limits<TKey>::max(),
54 FKey fKey = [](T const& key) { return key; })
55{
56 using IndexType = std::iterator_traits<TWorkBegin>::value_type;
57 static_assert(
58 std::is_integral_v<IndexType> and not std::is_same_v<IndexType, bool>,
59 "Work index must be range over integers");
60 using KeyType = std::invoke_result_t<FKey, T>;
61 static_assert(std::is_integral_v<KeyType>, "Key type must be integral");
62 auto const n = std::distance(vb, ve);
63 if (n == 0)
64 return;
65 // Find key offset
66 if (keyMin == std::numeric_limits<KeyType>::max())
67 for (auto it = vb; it != ve; ++it)
68 keyMin = std::min(keyMin, fKey(*it));
69 // Count occurrences
70 for (auto it = vb; it != ve; ++it)
71 {
72 KeyType key = fKey(*it);
73 KeyType j = key - keyMin;
74 ++(*(wb + j));
75 }
76 // Compute prefix sum
77 std::exclusive_scan(wb, we, wb, IndexType(0));
78 // Sort in place.
79 // NOTE: Taken from
80 // [SO](https://stackoverflow.com/questions/15682100/sorting-in-linear-time-and-in-place)
81 for (auto i = n - 1; i >= 0; --i)
82 {
83 T val = *(vb + i);
84 KeyType key = fKey(val) - keyMin;
85 IndexType j = *(wb + key); // counts[key]
86 if (j < i)
87 {
88 do
89 {
90 ++(*(wb + key)); // ++counts[key]
91 std::swap(val, *(vb + j)); // swap(val, a[j])
92 key = fKey(val) - keyMin;
93 j = *(wb + key); // j <- counts[key]
94 } while (j < i);
95 // Move final value into place.
96 *(vb + i) = val;
97 }
98 }
99}
100
112template <
113 std::random_access_iterator TValuesBegin,
114 std::random_access_iterator TValuesEnd,
115 std::random_access_iterator TWorkBegin,
116 class FKey>
117void PrefixSumFromSortedKeys(TValuesBegin vb, TValuesEnd ve, TWorkBegin wb, FKey fKey)
118{
119 using KeyType =
120 std::invoke_result_t<FKey, typename std::iterator_traits<TValuesBegin>::value_type>;
121 static_assert(std::is_integral_v<KeyType>, "Key type must be integral");
122 using IndexType = std::iterator_traits<TWorkBegin>::value_type;
123 static_assert(
124 std::is_integral_v<IndexType> and not std::is_same_v<IndexType, bool>,
125 "Work index must be range over integers");
126 if (vb == ve)
127 return;
128 KeyType key = fKey(*vb);
129 *wb = IndexType(0);
130 auto wit = wb;
131 for (auto it = vb; it != ve; ++it)
132 {
133 auto keyNext = fKey(*it);
134 if (key != keyNext)
135 {
136 key = keyNext;
137 *(wit + 1) = *wit;
138 ++wit;
139 }
140 ++(*wit);
141 }
142}
143
144} // namespace pbat::common
145
146#endif // PBAT_COMMON_COUNTINGSORT_H
Common functionality.
Definition ArgSort.h:20
void CountingSort(TWorkBegin wb, TWorkEnd we, TValuesBegin vb, TValuesEnd ve, TKey keyMin=std::numeric_limits< TKey >::max(), FKey fKey=[](T const &key) { return key;})
Counting sort.
Definition CountingSort.h:48
void PrefixSumFromSortedKeys(TValuesBegin vb, TValuesEnd ve, TWorkBegin wb, FKey fKey)
Definition CountingSort.h:117