1
0
mirror of https://github.com/chai2010/advanced-go-programming-book.git synced 2025-05-24 12:32:21 +00:00

ch2-6: 提炼 qsort 例子

This commit is contained in:
chai2010 2018-04-27 10:53:31 +08:00
parent ffa45e65ca
commit 84718a8e50
6 changed files with 136 additions and 214 deletions

View File

@ -6,14 +6,22 @@ package main
/* /*
#include <stdlib.h> #include <stdlib.h>
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* pa = (int*)a;
const int* pb = (int*)b; const int* pb = (int*)b;
return *pa - *pb; return *pa - *pb;
} }
static void qsort_proxy(int* values, size_t len, size_t elemsize) { static int compare(const void* a, const void* b) {
qsort(values, len, sizeof(values[0]), compare); 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" import "C"
@ -21,14 +29,24 @@ import "C"
import "unsafe" import "unsafe"
import "fmt" 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() { func main() {
values := []int32{42, 9, 101, 95, 27, 25} values := []int32{42, 9, 101, 95, 27, 25}
C.qsort_proxy( qsort(unsafe.Pointer(&values[0]),
(*C.int)(unsafe.Pointer(&values[0])), C.size_t(len(values)), C.size_t(unsafe.Sizeof(values[0])),
C.size_t(len(values)), C.get_compare_ptr(), // static callback must use proxy get
C.size_t(unsafe.Sizeof(values[0])),
) )
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) fmt.Println(values)
} }

View File

@ -9,14 +9,6 @@ package main
typedef int (*qsort_cmp_func_t)(const void* a, const void* b); 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);
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 "C"
import ( import (
@ -24,20 +16,24 @@ import (
"unsafe" "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 //export go_qsort_compare
func go_qsort_compare(a, b unsafe.Pointer) C.int { func go_qsort_compare(a, b unsafe.Pointer) C.int {
pa := (*C.int)(a) pa := (*C.int)(a)
pb := (*C.int)(b) pb := (*C.int)(b)
return C.int(*pa - *pb) 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)
}

View File

@ -3,6 +3,10 @@
package main package main
import (
"fmt"
)
/* /*
#include <stdlib.h> #include <stdlib.h>
@ -11,25 +15,40 @@ extern int go_qsort_compare(void* a, void* b);
*/ */
import "C" import "C"
import ( import (
"fmt" "sync"
"unsafe" "unsafe"
) )
func main() { var go_qsort_compare_info struct {
values := []int32{42, 9, 101, 95, 27, 25} fn func(a, b unsafe.Pointer) int
sync.Mutex
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 //export go_qsort_compare
func go_qsort_compare(a, b unsafe.Pointer) C.int { func go_qsort_compare(a, b unsafe.Pointer) C.int {
pa := (*C.int)(a) return C.int(go_qsort_compare_info.fn(a, b))
pb := (*C.int)(b) }
return C.int(*pa - *pb) 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)
} }

View File

@ -3,48 +3,85 @@
package main package main
import (
"fmt"
)
/* /*
#include <stdlib.h> #include <stdlib.h>
typedef int (*qsort_cmp_func_t)(const void* a, const void* b); 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 "C"
import ( import (
"fmt"
"reflect"
"sync" "sync"
"unsafe" "unsafe"
) )
func main() { var go_qsort_compare_info struct {
values := []int32{42, 9, 101, 95, 27, 25} slice interface{}
base uintptr
elemsize uintptr
fn func(a, b int) int
sync.Mutex
}
go_qsort_compare_info.Lock() //export go_qsort_compare_save_base
defer go_qsort_compare_info.Unlock() func go_qsort_compare_save_base(base unsafe.Pointer) {
go_qsort_compare_info.base = uintptr(base)
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 //export go_qsort_compare
func go_qsort_compare(a, b unsafe.Pointer) C.int { 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 { func qsort(slice interface{}, fn func(a, b int) int) {
fn func(a, b unsafe.Pointer) C.int sv := reflect.ValueOf(slice)
sync.RWMutex 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)
} }

View File

@ -1,56 +0,0 @@
// Copyright © 2018 ChaiShushan <chaishushan{AT}gmail.com>.
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
package main
import (
"fmt"
)
/*
#include <stdlib.h>
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
}

View File

@ -1,92 +0,0 @@
// Copyright © 2018 ChaiShushan <chaishushan{AT}gmail.com>.
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
package main
/*
#include <stdlib.h>
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
}