1212#include "internal/ttp_impl.hpp"
1313#include "internal/thread_impl.hpp"
1414
15+ namespace poolstl {
16+ /**
17+ * NOTE: Iterators are expected to be random access.
18+ *
19+ * Like `std::sort`, but allows specifying the sequential sort method, which must have the
20+ * same signature as the comparator version of `std::sort`.
21+ *
22+ * Implemented as a high-level quicksort that delegates to `sort_func`, in parallel, once the range has been
23+ * sufficiently partitioned.
24+ */
25+ template <class ExecPolicy, class RandIt, class Compare>
26+ poolstl::internal::enable_if_poolstl_policy<ExecPolicy, void>
27+ pluggable_sort(ExecPolicy &&policy, RandIt first, RandIt last, Compare comp,
28+ void (sort_func)(RandIt, RandIt, Compare) = std::sort) {
29+ if (poolstl::internal::is_seq<ExecPolicy>(policy)) {
30+ sort_func(first, last, comp);
31+ return;
32+ }
33+
34+ // Parallel partition.
35+ // The partition_p2 method spawns and waits for its own child task. A deadlock is possible if all worker
36+ // threads are waiting for tasks that in turn have to workers to execute them. This is only an issue because
37+ // our thread pool does not have the concept of dependencies.
38+ // So ensure
39+ auto& task_pool = *policy.pool();
40+ std::atomic<int> allowed_parallel_partitions{(int)task_pool.get_num_threads() / 2};
41+
42+ auto part_func = [&task_pool, &allowed_parallel_partitions](RandIt chunk_first, RandIt chunk_last,
43+ poolstl::internal::pivot_predicate<Compare,
44+ typename std::iterator_traits<RandIt>::value_type> pred) {
45+ if (allowed_parallel_partitions.fetch_sub(1) > 0) {
46+ return poolstl::internal::partition_p2(task_pool, chunk_first, chunk_last, pred);
47+ } else {
48+ return std::partition(chunk_first, chunk_last, pred);
49+ }
50+ };
51+
52+ poolstl::internal::parallel_quicksort(std::forward<ExecPolicy>(policy), first, last, comp, sort_func, part_func,
53+ poolstl::internal::quicksort_pivot<RandIt>);
54+ }
55+
56+ /**
57+ * NOTE: Iterators are expected to be random access.
58+ *
59+ * Like `std::sort`, but allows specifying the sequential sort method, which must have the
60+ * same signature as the comparator version of `std::sort`.
61+ *
62+ * Implemented as a parallel high-level quicksort that delegates to `sort_func` once the range has been
63+ * sufficiently partitioned.
64+ */
65+ template <class ExecPolicy, class RandIt>
66+ poolstl::internal::enable_if_poolstl_policy<ExecPolicy, void>
67+ pluggable_sort(ExecPolicy &&policy, RandIt first, RandIt last,
68+ void (sort_func)(RandIt, RandIt,
69+ std::less<typename std::iterator_traits<RandIt>::value_type>) = std::sort){
70+ using T = typename std::iterator_traits<RandIt>::value_type;
71+ pluggable_sort(std::forward<ExecPolicy>(policy), first, last, std::less<T>(), sort_func);
72+ }
73+ }
74+
1575namespace std {
1676
1777 /**
@@ -209,6 +269,22 @@ namespace std {
209269 return last;
210270 }
211271
272+ /**
273+ * NOTE: Iterators are expected to be random access.
274+ * See std::partition https://en.cppreference.com/w/cpp/algorithm/partition
275+ *
276+ * Current implementation uses at most 2 threads.
277+ */
278+ template <class ExecPolicy, class RandIt, class Predicate>
279+ poolstl::internal::enable_if_poolstl_policy<ExecPolicy, RandIt>
280+ partition(ExecPolicy &&policy, RandIt first, RandIt last, Predicate pred) {
281+ if (poolstl::internal::is_seq<ExecPolicy>(policy)) {
282+ return std::partition(first, last, pred);
283+ }
284+
285+ return poolstl::internal::partition_p2(*policy.pool(), first, last, pred);
286+ }
287+
212288 /**
213289 * NOTE: Iterators are expected to be random access.
214290 * See std::sort https://en.cppreference.com/w/cpp/algorithm/sort
@@ -221,11 +297,7 @@ namespace std {
221297 return;
222298 }
223299
224- poolstl::internal::parallel_quicksort(std::forward<ExecPolicy>(policy), first, last, comp,
225- std::sort<RandIt, Compare>,
226- std::partition<RandIt, poolstl::internal::pivot_predicate<Compare,
227- typename std::iterator_traits<RandIt>::value_type>>,
228- poolstl::internal::quicksort_pivot<RandIt>);
300+ poolstl::pluggable_sort(std::forward<ExecPolicy>(policy), first, last, comp, std::sort<RandIt, Compare>);
229301 }
230302
231303 /**
@@ -377,48 +449,6 @@ namespace poolstl {
377449 (void*)nullptr, 1, construct, f);
378450 }
379451
380- /**
381- * NOTE: Iterators are expected to be random access.
382- *
383- * Like `std::sort`, but allows specifying the sequential sort method, which must have the
384- * same signature as the comparator version of `std::sort`.
385- *
386- * Implemented as a high-level quicksort that delegates to `sort_func`, in parallel, once the range has been
387- * sufficiently partitioned.
388- */
389- template <class ExecPolicy, class RandIt, class Compare>
390- poolstl::internal::enable_if_poolstl_policy<ExecPolicy, void>
391- pluggable_sort(ExecPolicy &&policy, RandIt first, RandIt last, Compare comp,
392- void (sort_func)(RandIt, RandIt, Compare) = std::sort) {
393- if (poolstl::internal::is_seq<ExecPolicy>(policy)) {
394- sort_func(first, last, comp);
395- return;
396- }
397-
398- poolstl::internal::parallel_quicksort(std::forward<ExecPolicy>(policy), first, last, comp, sort_func,
399- std::partition<RandIt, poolstl::internal::pivot_predicate<Compare,
400- typename std::iterator_traits<RandIt>::value_type>>,
401- poolstl::internal::quicksort_pivot<RandIt>);
402- }
403-
404- /**
405- * NOTE: Iterators are expected to be random access.
406- *
407- * Like `std::sort`, but allows specifying the sequential sort method, which must have the
408- * same signature as the comparator version of `std::sort`.
409- *
410- * Implemented as a parallel high-level quicksort that delegates to `sort_func` once the range has been
411- * sufficiently partitioned.
412- */
413- template <class ExecPolicy, class RandIt>
414- poolstl::internal::enable_if_poolstl_policy<ExecPolicy, void>
415- pluggable_sort(ExecPolicy &&policy, RandIt first, RandIt last,
416- void (sort_func)(RandIt, RandIt,
417- std::less<typename std::iterator_traits<RandIt>::value_type>) = std::sort){
418- using T = typename std::iterator_traits<RandIt>::value_type;
419- pluggable_sort(std::forward<ExecPolicy>(policy), first, last, std::less<T>(), sort_func);
420- }
421-
422452 /**
423453 * NOTE: Iterators are expected to be random access.
424454 *
0 commit comments