builtin: implement array.sort_with_compare_context
parent
eb772cfcf9
commit
17226830c8
|
@ -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.
|
||||
|
|
|
@ -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)
|
|
@ -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)
|
|
@ -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)
|
|
@ -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))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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',
|
||||
]
|
||||
}
|
|
@ -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>
|
||||
|
|
Loading…
Reference in New Issue