add insertion sort (#1225)

This commit is contained in:
Alex Anderson
2024-07-08 09:07:04 -07:00
committed by Christoffer Lerno
parent 4ea50a8a85
commit 900c1152d3
6 changed files with 184 additions and 8 deletions

View File

@@ -3,8 +3,8 @@ module std::sort;
/**
* Perform a binary search over the sorted array and return the index
* in [0, array.len) where x would be inserted or cmp(i) is true and cmp(j) is true for j in [i, array.len).
* @require $defined(list[0]) && $defined(list.len) "The list must be indexable"
* @require $or(@typeid(cmp) == void*.typeid, @is_comparer(cmp, list)) "Expected a comparison function which compares values"
* @require @is_sortable(list) "The list must be sortable"
* @require $or(@typeid(cmp) == void*.typeid, @is_cmp_fn(cmp, list)) "Expected a comparison function which compares values"
**/
macro usz binarysearch(list, x, cmp = null) @builtin
{

View File

@@ -0,0 +1,58 @@
module std::sort;
import std::sort::is;
/**
* Sort list using the quick sort algorithm.
* @require @is_sortable(list) "The list must be indexable and support .len or .len()"
* @require $or(@typeid(cmp) == void*.typeid, @is_cmp_fn(cmp, list)) "Expected a comparison function which compares values"
**/
macro insertionsort(list, cmp = null) @builtin
{
usz len = sort::@len_from_list(list);
is::isort(<$typeof(list), $typeof(cmp)>)(list, 0, (isz)len, cmp);
}
module std::sort::is(<Type, Comparer>);
def ElementType = $typeof(Type{}[0]);
fn void isort(Type list, usz low, usz high, Comparer comp)
{
var $no_cmp = Comparer.typeid == void*.typeid;
var $cmp_by_value = $and(!$no_cmp, Comparer.params[0] == @typeid(list[0]));
var $has_get_ref = $defined(&list[0]);
assert(sort::@is_sortable(list));
for (usz i = low; i < high; ++i)
{
usz j = i;
for (;j > low;)
{
$if $has_get_ref:
ElementType *rhs = &list[j];
ElementType *lhs = &list[--j];
$switch
$case $cmp_by_value:
if (comp(*rhs, *lhs) >= 0) break;
$case !$no_cmp:
if (comp(rhs, lhs) >= 0) break;
$default:
if (!less(*rhs, *lhs)) break;
$endswitch
@swap(*rhs, *lhs);
$else
usz r = j;
--j;
$switch
$case $cmp_by_value:
if (comp(list[r], list[j]) >= 0) break;
$case !$no_cmp:
if (comp(&list[r], &list[j]) >= 0) break;
$default:
if (!less(list[r], list[j])) break;
$endswitch
@swap(list[r], list[j]);
$endif
}
}
}

View File

@@ -3,15 +3,13 @@ import std::sort::qs;
/**
* Sort list using the quick sort algorithm.
* @require $defined(list[0]) && $defined(list.len) "The list must be indexable and support .len or .len()"
* @require $or(@typeid(cmp) == void*.typeid, @is_comparer(cmp, list)) "Expected a comparison function which compares values"
* @require @is_sortable(list) "The list must be indexable and support .len or .len()"
* @require $or(@typeid(cmp) == void*.typeid, @is_cmp_fn(cmp, list)) "Expected a comparison function which compares values"
**/
macro quicksort(list, cmp = null) @builtin
{
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);
qs::qsort(<$typeof(list), $typeof(cmp)>)(list, 0, (isz)len - 1, cmp);
}
module std::sort::qs(<Type, Comparer>);

View File

@@ -10,7 +10,21 @@ macro usz @len_from_list(&list)
$endif
}
macro bool @is_comparer(#cmp, #list)
macro bool @is_sortable(#list)
{
$switch
$case !$defined(#list[0]):
return false;
$case !$defined(#list.len):
return false;
$case $and($defined(&#list[0]) && !types::is_same($typeof(&#list[0]), $typeof(#list[0])*)):
return false;
$default:
return true;
$endswitch;
}
macro bool @is_cmp_fn(#cmp, #list)
{
var $Type = $typeof(#cmp);
$switch