Mercurial > foo_out_sdl
diff foosdk/sdk/foobar2000/SDK/foosort.cpp @ 1:20d02a178406 default tip
*: check in everything else
yay
| author | Paper <paper@tflc.us> |
|---|---|
| date | Mon, 05 Jan 2026 02:15:46 -0500 |
| parents | |
| children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/foosdk/sdk/foobar2000/SDK/foosort.cpp Mon Jan 05 02:15:46 2026 -0500 @@ -0,0 +1,162 @@ +#include "foobar2000-sdk-pch.h" +#include "foosort.h" +#include "threadPool.h" +#include "genrand.h" + +#define FOOSORT_PROFILING 0 + +namespace { +#if FOOSORT_PROFILING + typedef pfc::hires_timer foosort_timer; +#endif + + class foosort { + public: + foosort(pfc::sort_callback & cb, abort_callback & a) : m_abort(a), p_callback(cb) {} + + foosort fork() { + foosort ret ( * this ); + ret.genrand = genrand_service::g_create(); + return ret; + } + + size_t myrand(size_t cnt) { + PFC_ASSERT(cnt == (uint32_t)cnt); + return genrand->genrand((uint32_t)cnt); + } + + void squaresort(t_size const p_base, t_size const p_count) { + const t_size max = p_base + p_count; + for (t_size walk = p_base + 1; walk < max; ++walk) { + for (t_size prev = p_base; prev < walk; ++prev) { + p_callback.swap_check(prev, walk); + } + } + } + + + void _sort_2elem_helper(t_size & p_elem1, t_size & p_elem2) { + if (p_callback.compare(p_elem1, p_elem2) > 0) pfc::swap_t(p_elem1, p_elem2); + } + + t_size _pivot_helper(t_size const p_base, t_size const p_count) { + PFC_ASSERT(p_count > 2); + + //t_size val1 = p_base, val2 = p_base + (p_count / 2), val3 = p_base + (p_count - 1); + + t_size val1 = myrand(p_count), val2 = myrand(p_count - 1), val3 = myrand(p_count - 2); + if (val2 >= val1) val2++; + if (val3 >= val1) val3++; + if (val3 >= val2) val3++; + + val1 += p_base; val2 += p_base; val3 += p_base; + + _sort_2elem_helper(val1, val2); + _sort_2elem_helper(val1, val3); + _sort_2elem_helper(val2, val3); + + return val2; + } + + void newsort(t_size const p_base, t_size const p_count, size_t concurrency) { + if (p_count <= 4) { + squaresort(p_base, p_count); + return; + } + + this->m_abort.check(); +#if FOOSORT_PROFILING + foosort_timer t; + if ( concurrency > 1 ) t.start(); +#endif + + t_size pivot = _pivot_helper(p_base, p_count); + + { + const t_size target = p_base + p_count - 1; + if (pivot != target) { + p_callback.swap(pivot, target); pivot = target; + } + } + + + t_size partition = p_base; + { + bool asdf = false; + for (t_size walk = p_base; walk < pivot; ++walk) { + const int comp = p_callback.compare(walk, pivot); + bool trigger = false; + if (comp == 0) { + trigger = asdf; + asdf = !asdf; + } else if (comp < 0) { + trigger = true; + } + if (trigger) { + if (partition != walk) p_callback.swap(partition, walk); + partition++; + } + } + } + if (pivot != partition) { + p_callback.swap(pivot, partition); pivot = partition; + } + + const auto base1 = p_base, count1 = pivot - p_base; + const auto base2 = pivot + 1, count2 = p_count - (pivot + 1 - p_base); + + if (concurrency > 1) { + + size_t total = count1 + count2; + size_t con1 = (size_t)((uint64_t)count1 * (uint64_t)concurrency / (uint64_t)total); + if (con1 < 1) con1 = 1; + if (con1 > concurrency - 1) con1 = concurrency - 1; + size_t con2 = concurrency - con1; + +#if FOOSORT_PROFILING + FB2K_console_formatter() << "foosort pass: " << p_base << "+" << p_count << "(" << concurrency << ") took " << t.queryString(); + FB2K_console_formatter() << "foosort forking: " << base1 << "+" << count1 << "(" << con1 << ") + " << base2 << "+" << count2 << "(" << con2 << ")"; +#endif + pfc::counter cnt; + fb2k::cpuThreadPool::runMultiHelper([&] { + try { + switch (cnt++) { + case 0: + { foosort subsort = fork(); subsort.newsort(base1, count1, con1); } + break; + case 1: + newsort(base2, count2, con2); + break; + } + } catch (exception_aborted const &) {} + }, 2); + m_abort.check(); + } else { + newsort(base1, count1, 1); + newsort(base2, count2, 1); + } + } + private: + abort_callback & m_abort; + pfc::sort_callback & p_callback; + genrand_service::ptr genrand = genrand_service::g_create(); + }; + + + +} +namespace fb2k { + void sort(pfc::sort_callback & cb, size_t count, size_t concurrency, abort_callback & aborter) { +#ifdef FOOSORT_LIMIT_THREADS + if (concurrency > FOOSORT_LIMIT_THREADS) concurrency = FOOSORT_LIMIT_THREADS; +#endif +#if FOOSORT_PROFILING + foosort_timer t; t.start(); +#endif + foosort theFooSort(cb, aborter); + theFooSort.newsort(0, count, concurrency); +#if FOOSORT_PROFILING + FB2K_console_formatter() << "foosort took: " << t.queryString(); +#endif + } +}
