diff --git a/examples/ch2-06-qsort/v2-qsort/main.go b/examples/ch2-06-qsort/v2-qsort/main.go index 6a231ef..c63fa06 100644 --- a/examples/ch2-06-qsort/v2-qsort/main.go +++ b/examples/ch2-06-qsort/v2-qsort/main.go @@ -6,14 +6,22 @@ package main /* #include -static int compare(const void* a, const void* b) { +typedef int (*qsort_cmp_func_t)(const void* a, const void* b); + +// disable static +int qsort_compare_callback(const void* a, const void* b) { const int* pa = (int*)a; const int* pb = (int*)b; return *pa - *pb; } -static void qsort_proxy(int* values, size_t len, size_t elemsize) { - qsort(values, len, sizeof(values[0]), compare); +static int compare(const void* a, const void* b) { + const int* pa = (int*)a; + const int* pb = (int*)b; + return *pa - *pb; +} +static qsort_cmp_func_t get_compare_ptr() { + return compare; } */ import "C" @@ -21,14 +29,24 @@ import "C" import "unsafe" import "fmt" +func qsort(base unsafe.Pointer, num, size C.size_t, cmp C.qsort_cmp_func_t) { + C.qsort(base, num, size, C.qsort_cmp_func_t(cmp)) +} + func main() { values := []int32{42, 9, 101, 95, 27, 25} - C.qsort_proxy( - (*C.int)(unsafe.Pointer(&values[0])), - C.size_t(len(values)), - C.size_t(unsafe.Sizeof(values[0])), + qsort(unsafe.Pointer(&values[0]), + C.size_t(len(values)), C.size_t(unsafe.Sizeof(values[0])), + C.get_compare_ptr(), // static callback must use proxy get ) + fmt.Println(values) + values = []int32{42, 9, 101, 95, 27, 25} + + qsort(unsafe.Pointer(&values[0]), + C.size_t(len(values)), C.size_t(unsafe.Sizeof(values[0])), + C.qsort_cmp_func_t(unsafe.Pointer(C.qsort_compare_callback)), + ) fmt.Println(values) } diff --git a/examples/ch2-06-qsort/v3-qsort/main.go b/examples/ch2-06-qsort/v3-qsort/main.go index 02409fc..2d423dc 100644 --- a/examples/ch2-06-qsort/v3-qsort/main.go +++ b/examples/ch2-06-qsort/v3-qsort/main.go @@ -9,14 +9,6 @@ package main typedef int (*qsort_cmp_func_t)(const void* a, const void* b); extern int go_qsort_compare(void* a, void* b); - -static int compare(const void* a, const void* b) { - return go_qsort_compare((void*)(a), (void*)(b)); -} - -static qsort_cmp_func_t get_compare_ptr() { - return compare; -} */ import "C" import ( @@ -24,20 +16,24 @@ import ( "unsafe" ) -func main() { - values := []int32{42, 9, 101, 95, 27, 25} - - C.qsort(unsafe.Pointer(&values[0]), - C.size_t(len(values)), C.size_t(unsafe.Sizeof(values[0])), - C.get_compare_ptr(), - ) - - fmt.Println(values) -} - //export go_qsort_compare func go_qsort_compare(a, b unsafe.Pointer) C.int { pa := (*C.int)(a) pb := (*C.int)(b) return C.int(*pa - *pb) } + +func qsort(base unsafe.Pointer, num, size C.size_t, cmp C.qsort_cmp_func_t) { + C.qsort(base, num, size, C.qsort_cmp_func_t(cmp)) +} + +func main() { + values := []int32{42, 9, 101, 95, 27, 25} + + qsort(unsafe.Pointer(&values[0]), + C.size_t(len(values)), C.size_t(unsafe.Sizeof(values[0])), + C.qsort_cmp_func_t(unsafe.Pointer(C.go_qsort_compare)), + ) + + fmt.Println(values) +} diff --git a/examples/ch2-06-qsort/v4-qsort/main.go b/examples/ch2-06-qsort/v4-qsort/main.go index 65a2fb3..a4670f3 100644 --- a/examples/ch2-06-qsort/v4-qsort/main.go +++ b/examples/ch2-06-qsort/v4-qsort/main.go @@ -3,6 +3,10 @@ package main +import ( + "fmt" +) + /* #include @@ -11,25 +15,40 @@ extern int go_qsort_compare(void* a, void* b); */ import "C" import ( - "fmt" + "sync" "unsafe" ) -func main() { - values := []int32{42, 9, 101, 95, 27, 25} - - C.qsort(unsafe.Pointer(&values[0]), - C.size_t(len(values)), C.size_t(unsafe.Sizeof(values[0])), - (C.qsort_cmp_func_t)(unsafe.Pointer(C.go_qsort_compare)), - ) - - fmt.Println(values) +var go_qsort_compare_info struct { + fn func(a, b unsafe.Pointer) int + sync.Mutex } //export go_qsort_compare func go_qsort_compare(a, b unsafe.Pointer) C.int { - pa := (*C.int)(a) - pb := (*C.int)(b) - - return C.int(*pa - *pb) + return C.int(go_qsort_compare_info.fn(a, b)) +} + +func qsort(base unsafe.Pointer, num, size int, cmp func(a, b unsafe.Pointer) int) { + go_qsort_compare_info.Lock() + defer go_qsort_compare_info.Unlock() + + go_qsort_compare_info.fn = cmp + + C.qsort(base, C.size_t(num), C.size_t(size), + C.qsort_cmp_func_t(C.go_qsort_compare), + ) +} + +func main() { + values := []int32{42, 9, 101, 95, 27, 25} + + qsort(unsafe.Pointer(&values[0]), len(values), int(unsafe.Sizeof(values[0])), + func(a, b unsafe.Pointer) int { + pa, pb := (*C.int)(a), (*C.int)(b) + return int(*pa - *pb) + }, + ) + + fmt.Println(values) } diff --git a/examples/ch2-06-qsort/v5-qsort/main.go b/examples/ch2-06-qsort/v5-qsort/main.go index 1b125da..c6b3f0a 100644 --- a/examples/ch2-06-qsort/v5-qsort/main.go +++ b/examples/ch2-06-qsort/v5-qsort/main.go @@ -3,48 +3,85 @@ package main -import ( - "fmt" -) - /* #include typedef int (*qsort_cmp_func_t)(const void* a, const void* b); -extern int go_qsort_compare(void* a, void* b); + +extern int go_qsort_compare(void* a, void* b); */ import "C" + import ( + "fmt" + "reflect" "sync" "unsafe" ) -func main() { - values := []int32{42, 9, 101, 95, 27, 25} +var go_qsort_compare_info struct { + slice interface{} + base uintptr + elemsize uintptr + fn func(a, b int) int + sync.Mutex +} - go_qsort_compare_info.Lock() - defer go_qsort_compare_info.Unlock() - - go_qsort_compare_info.fn = func(a, b unsafe.Pointer) C.int { - pa := (*C.int)(a) - pb := (*C.int)(b) - return C.int(*pa - *pb) - } - - C.qsort(unsafe.Pointer(&values[0]), - C.size_t(len(values)), C.size_t(unsafe.Sizeof(values[0])), - (C.qsort_cmp_func_t)(unsafe.Pointer(C.go_qsort_compare)), - ) - - fmt.Println(values) +//export go_qsort_compare_save_base +func go_qsort_compare_save_base(base unsafe.Pointer) { + go_qsort_compare_info.base = uintptr(base) } //export go_qsort_compare func go_qsort_compare(a, b unsafe.Pointer) C.int { - return go_qsort_compare_info.fn(a, b) + if go_qsort_compare_info.base == 0 { + sv := reflect.ValueOf(go_qsort_compare_info.slice) + go_qsort_compare_info.base = uintptr(unsafe.Pointer(sv.Index(0).Addr().Pointer())) + } + + var ( + // array memory is locked + base = go_qsort_compare_info.base + elemsize = go_qsort_compare_info.elemsize + ) + + i := int((uintptr(a) - base) / elemsize) + j := int((uintptr(b) - base) / elemsize) + + return C.int(go_qsort_compare_info.fn(i, j)) } -var go_qsort_compare_info struct { - fn func(a, b unsafe.Pointer) C.int - sync.RWMutex +func qsort(slice interface{}, fn func(a, b int) int) { + sv := reflect.ValueOf(slice) + if sv.Kind() != reflect.Slice { + panic(fmt.Sprintf("qsort called with non-slice value of type %T", slice)) + } + if sv.Len() == 0 { + return + } + + go_qsort_compare_info.Lock() + defer go_qsort_compare_info.Unlock() + + // baseMem = unsafe.Pointer(sv.Index(0).Addr().Pointer()) + // baseMem maybe moved, so must saved after call C.fn + go_qsort_compare_info.slice = slice + go_qsort_compare_info.elemsize = sv.Type().Elem().Size() + go_qsort_compare_info.fn = fn + + C.qsort( + unsafe.Pointer(sv.Index(0).Addr().Pointer()), + C.size_t(sv.Len()), C.size_t(sv.Type().Elem().Size()), + C.qsort_cmp_func_t(C.go_qsort_compare), + ) +} + +func main() { + values := []int64{42, 9, 101, 95, 27, 25} + + qsort(values, func(i, j int) int { + return int(values[i] - values[j]) + }) + + fmt.Println(values) } diff --git a/examples/ch2-06-qsort/v6-qsort/main.go b/examples/ch2-06-qsort/v6-qsort/main.go deleted file mode 100644 index 497e210..0000000 --- a/examples/ch2-06-qsort/v6-qsort/main.go +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright © 2018 ChaiShushan . -// License: https://creativecommons.org/licenses/by-nc-sa/4.0/ - -package main - -import ( - "fmt" -) - -/* -#include - -typedef int (*qsort_cmp_func_t)(const void* a, const void* b); -extern int go_qsort_compare(void* a, void* b); -*/ -import "C" -import ( - "sync" - "unsafe" -) - -func main() { - values := []int32{42, 9, 101, 95, 27, 25} - - qsort(values, func(a, b unsafe.Pointer) C.int { - pa := (*C.int)(a) - pb := (*C.int)(b) - return C.int(*pa - *pb) - }) - - fmt.Println(values) -} - -func qsort(values []int32, fn func(a, b unsafe.Pointer) C.int) { - go_qsort_compare_info.Lock() - defer go_qsort_compare_info.Unlock() - - go_qsort_compare_info.fn = fn - - C.qsort( - unsafe.Pointer(&values[0]), - C.size_t(len(values)), - C.size_t(unsafe.Sizeof(values[0])), - (C.qsort_cmp_func_t)(unsafe.Pointer(C.go_qsort_compare)), - ) -} - -//export go_qsort_compare -func go_qsort_compare(a, b unsafe.Pointer) C.int { - return go_qsort_compare_info.fn(a, b) -} - -var go_qsort_compare_info struct { - fn func(a, b unsafe.Pointer) C.int - sync.RWMutex -} diff --git a/examples/ch2-06-qsort/v7-qsort/main.go b/examples/ch2-06-qsort/v7-qsort/main.go deleted file mode 100644 index 717333b..0000000 --- a/examples/ch2-06-qsort/v7-qsort/main.go +++ /dev/null @@ -1,92 +0,0 @@ -// Copyright © 2018 ChaiShushan . -// License: https://creativecommons.org/licenses/by-nc-sa/4.0/ - -package main - -/* -#include - -typedef int (*qsort_cmp_func_t)(const void* a, const void* b); - -extern int go_qsort_compare(void* a, void* b); -extern void go_qsort_compare_save_base(void* base); - -static void -qsort_proxy( - void* base, size_t num, size_t size, - int (*compare)(const void* a, const void* b) -) { - go_qsort_compare_save_base(base); - qsort(base, num, size, compare); -} -*/ -import "C" - -import ( - "fmt" - "reflect" - "sync" - "unsafe" -) - -func main() { - values := []int64{42, 9, 101, 95, 27, 25} - - fmt.Println(values) - defer fmt.Println(values) - - qsort(values, func(i, j int) int { - return int(values[i] - values[j]) - }) -} - -func qsort(slice interface{}, fn func(a, b int) int) { - sv := reflect.ValueOf(slice) - if sv.Kind() != reflect.Slice { - panic(fmt.Sprintf("qsort called with non-slice value of type %T", slice)) - } - if sv.Len() == 0 { - return - } - - go_qsort_compare_info.Lock() - defer go_qsort_compare_info.Unlock() - - // baseMem = unsafe.Pointer(sv.Index(0).Addr().Pointer()) - // baseMem maybe moved, so must saved after call C.fn - go_qsort_compare_info.elemsize = sv.Type().Elem().Size() - go_qsort_compare_info.fn = fn - - C.qsort_proxy( - unsafe.Pointer(unsafe.Pointer(sv.Index(0).Addr().Pointer())), - C.size_t(sv.Len()), - C.size_t(sv.Type().Elem().Size()), - (C.qsort_cmp_func_t)(unsafe.Pointer(C.go_qsort_compare)), - ) -} - -//export go_qsort_compare -func go_qsort_compare(a, b unsafe.Pointer) C.int { - var ( - // array memory is locked - base = go_qsort_compare_info.base - elemsize = go_qsort_compare_info.elemsize - ) - - i := int((uintptr(a) - base) / elemsize) - j := int((uintptr(b) - base) / elemsize) - - return C.int(go_qsort_compare_info.fn(i, j)) -} - -//export go_qsort_compare_save_base -func go_qsort_compare_save_base(base unsafe.Pointer) { - go_qsort_compare_info.base = uintptr(base) -} - -var go_qsort_compare_info struct { - base uintptr - elemsize uintptr - fn func(a, b int) int - sync.RWMutex -}