builtin: implement array.sort_with_compare_context

pull/13721/head
Delyan Angelov 2022-03-12 18:12:57 +02:00
parent eb772cfcf9
commit 17226830c8
No known key found for this signature in database
GPG Key ID: 66886C0F12D595ED
7 changed files with 88 additions and 1 deletions

View File

@ -756,12 +756,22 @@ pub fn (mut a array) sort(callback fn (voidptr, voidptr) int)
// ```
pub fn (mut a array) sort_with_compare(callback fn (voidptr, voidptr) int) {
$if freestanding {
panic('sort does not work with -freestanding')
panic('sort_with_compare does not work with -freestanding')
} $else {
unsafe { vqsort(a.data, usize(a.len), usize(a.element_size), callback) }
}
}
pub fn (mut a array) sort_with_compare_context(callback fn (voidptr, voidptr, voidptr) int, context voidptr) {
$if freestanding {
panic('sort_with_compare_context does not work with -freestanding')
} $else {
unsafe {
vqsort_context(a.data, usize(a.len), usize(a.element_size), callback, context)
}
}
}
// contains determines whether an array includes a certain value among its elements
// It will return `true` if the array contains an element with this value.
// It is similar to `.any` but does not take an `it` expression.

View File

@ -0,0 +1,4 @@
module builtin
fn C.qsort_r(base voidptr, items usize, item_size usize, context voidptr, cb C.qsort_r_bsd_callback_func_context)
fn C.qsort_s(base voidptr, items usize, item_size usize, cb C.qsort_s_iso_callback_func_context, context voidptr)

View File

@ -0,0 +1,3 @@
module builtin
fn C.qsort_r(base voidptr, items usize, item_size usize, cb C.qsort_r_gnu_callback_func_context, context voidptr)

View File

@ -0,0 +1,3 @@
module builtin
fn C.qsort_s(base voidptr, items usize, item_size usize, cb C.qsort_s_windows_callback_func_context, context voidptr)

View File

@ -66,7 +66,41 @@ pub fn vmemset(s voidptr, c int, n int) voidptr {
type FnSortCB = fn (const_a voidptr, const_b voidptr) int
type FnSortContextCB = fn (const_a voidptr, const_b voidptr, context voidptr) int
[inline; unsafe]
fn vqsort(base voidptr, nmemb usize, size usize, sort_cb FnSortCB) {
C.qsort(base, nmemb, size, voidptr(sort_cb))
}
struct VIndirectQSortContext {
mut:
real_context voidptr
real_sort_cb FnSortContextCB
}
[inline; unsafe]
fn vqsort_context(base voidptr, nmemb usize, size usize, sort_cb FnSortContextCB, context voidptr) {
// See https://stackoverflow.com/questions/39560773/different-declarations-of-qsort-r-on-mac-and-linux
// ... and https://xkcd.com/927/ :-|
$if linux {
C.qsort_r(base, nmemb, size, voidptr(sort_cb), context)
} $else {
ic := VIndirectQSortContext{
real_context: context
real_sort_cb: sort_cb
}
$if windows {
cb := fn (context &VIndirectQSortContext, const_a voidptr, const_b voidptr) int {
return context.real_sort_cb(const_a, const_b, context.real_context)
}
C.qsort_s(base, nmemb, size, voidptr(cb), &ic)
} $else {
// macos, BSDs, probably other unixes too:
cb := fn (context &VIndirectQSortContext, const_a voidptr, const_b voidptr) int {
return context.real_sort_cb(const_a, const_b, context.real_context)
}
C.qsort_r(base, nmemb, size, &ic, voidptr(cb))
}
}
}

View File

@ -0,0 +1,29 @@
struct Context {
mut:
comparisons []string
}
fn test_sort_with_compare() {
mut a := ['hi', '1', '5', '3']
mut context := Context{}
a.sort_with_compare_context(fn (a &string, b &string, mut context Context) int {
context.comparisons << 'a: ${*a} | b: ${*b}'
if a < b {
return -1
}
if a > b {
return 1
}
return 0
}, context)
dump(a)
dump(context)
assert a == ['1', '3', '5', 'hi']
assert context.comparisons == [
'a: hi | b: 1',
'a: 5 | b: 3',
'a: 1 | b: 3',
'a: hi | b: 3',
'a: hi | b: 5',
]
}

View File

@ -478,6 +478,10 @@ const c_headers = c_helper_macros + c_unsigned_comparison_functions + c_common_m
r'
// c_headers
typedef int (*qsort_callback_func)(const void*, const void*);
typedef int (*qsort_s_iso_callback_func_context)(const void*, const void*, void*); // ISO C11, *optional* Annex K
typedef int (*qsort_s_windows_callback_func_context)(void*, const void*, const void*); // Windows
typedef int (*qsort_r_gnu_callback_func_context)(const void*, const void*, void*); // Linux, GNU
typedef int (*qsort_r_bsd_callback_func_context)(void*, const void*, const void*); // MacOS, BSD
#include <stdio.h> // TODO remove all these includes, define all function signatures and types manually
#include <stdlib.h>
#include <string.h>