std/lib/sort: update quicksort to use the new generics

Signed-off-by: Pierre Curto <pierre.curto@gmail.com>
This commit is contained in:
Pierre Curto
2023-07-08 11:40:51 +02:00
committed by Christoffer Lerno
parent 5f711408c0
commit 77b3214746
4 changed files with 46 additions and 108 deletions

View File

@@ -1,99 +1,45 @@
module std::sort::quicksort(<Type>);
import std::sort;
module std::sort;
import std::sort::qs;
macro quicksort(list, cmp = null)
{
var $Type = $typeof(list);
var $CmpType = $typeof(cmp);
usz len = sort::@len_from_list(list);
qs::qsort(<$Type, $CmpType>)(list, 0, (isz)len - 1, cmp);
}
module std::sort::qs(<Type, Comparer>);
def ElementType = $typeof(Type{}[0]);
def Comparer = fn int(ElementType, ElementType);
def ComparerRef = fn int(ElementType*, ElementType*);
const bool ELEMENT_COMPARABLE = $checks(ElementType x, greater(x, x));
fn void sort_fn(Type list, Comparer cmp)
{
usz len = sort::@len_from_list(list);
qsort_value(list, 0, (isz)len - 1, cmp);
}
fn void sort_ref_fn(Type list, ComparerRef cmp)
{
usz len = sort::@len_from_list(list);
qsort_ref(list, 0, (isz)len - 1, cmp);
}
fn void sort(Type list) @if(ELEMENT_COMPARABLE)
{
usz len = sort::@len_from_list(list);
qsort(list, 0, (isz)len - 1);
}
fn void qsort(Type list, isz low, isz high) @local @if(ELEMENT_COMPARABLE)
fn void qsort(Type list, isz low, isz high, Comparer cmp)
{
if (low < high)
{
isz p = partition(list, low, high);
qsort(list, low, p - 1);
qsort(list, p + 1, high);
isz p = partition(list, low, high, cmp);
qsort(list, low, p - 1, cmp);
qsort(list, p + 1, high, cmp);
}
}
fn void qsort_value(Type list, isz low, isz high, Comparer cmp) @local
{
if (low < high)
{
isz p = partition_value(list, low, high, cmp);
qsort_value(list, low, p - 1, cmp);
qsort_value(list, p + 1, high, cmp);
}
}
fn void qsort_ref(Type list, isz low, isz high, ComparerRef cmp) @local
{
if (low < high)
{
isz p = partition_ref(list, low, high, cmp);
qsort_ref(list, low, p - 1, cmp);
qsort_ref(list, p + 1, high, cmp);
}
}
fn isz partition(Type list, isz low, isz high) @inline @local
fn isz partition(Type list, isz low, isz high, Comparer cmp) @inline @local
{
ElementType pivot = list[high];
isz i = low - 1;
for (isz j = low; j < high; j++)
{
if (greater(list[j], pivot)) continue;
i++;
@swap(list[i], list[j]);
}
i++;
@swap(list[i], list[high]);
return i;
}
fn isz partition_value(Type list, isz low, isz high, Comparer cmp) @inline @private
{
ElementType pivot = list[high];
isz i = low - 1;
for (isz j = low; j < high; j++)
{
if (cmp(list[j], pivot) <= 0)
{
i++;
@swap(list[i], list[j]);
}
}
i++;
@swap(list[i], list[high]);
return i;
}
fn isz partition_ref(Type list, isz low, isz high, ComparerRef cmp) @inline @private
{
ElementType* pivot = &list[high];
isz i = low - 1;
for (isz j = low; j < high; j++)
{
if (cmp(&list[j], pivot) <= 0)
$if $checks(cmp(list[0], list[0])):
int res = cmp(list[j], pivot);
$else
$if $checks(cmp(&list[0], &list[0])):
int res = cmp(&list[j], &pivot);
$else
int res;
if (greater(list[j], pivot)) continue;
$endif
$endif
if (res <= 0)
{
i++;
@swap(list[i], list[j]);