latest SDK
This commit is contained in:
154
foobar2000/SDK/foosort.cpp
Normal file
154
foobar2000/SDK/foosort.cpp
Normal file
@@ -0,0 +1,154 @@
|
||||
#include "foobar2000.h"
|
||||
#include "foosort.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) {
|
||||
return genrand->genrand(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::thread2 other;
|
||||
other.startHere([&] {
|
||||
try {
|
||||
foosort subsort = fork();
|
||||
subsort.newsort(base1, count1, con1);
|
||||
} catch (exception_aborted) {}
|
||||
});
|
||||
try {
|
||||
newsort(base2, count2, con2);
|
||||
} catch (exception_aborted) {}
|
||||
other.waitTillDone();
|
||||
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) {
|
||||
#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
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user