package code

import (
	"fmt"
	"reflect"
	"testing"
	"unsafe"

	"github.com/stretchr/testify/assert"
)

func TestSliceArray(t *testing.T) {
	var arr = [...]int{1, 2, 3}
	var slice = []int{1, 2, 3}
	ModifyArray(arr)
	ModifySlice(slice)
	t.Logf("%v %v\n", arr, slice)
	assert.NotEqual(t, arr[2], 1)
	assert.Equal(t, slice[2], 1)
}

func ModifyArray(arr [3]int) {
	fmt.Println(arr)
	arr[2] = 1
}

func ModifySlice(slice []int) {
	fmt.Println(slice)
	slice[2] = 1
}

func TestSlice(t *testing.T) {
	slice := []int{1, 2, 3}
	arr := [...]int{1, 2, 3}
	fmt.Printf("切片：底层数组指针：%d 切片：指针%v reflect.SliceHeader: %+v\n",
		unsafe.SliceData(slice), unsafe.Pointer(&slice), (*reflect.SliceHeader)(unsafe.Pointer(&slice)))
	SlicePointer(slice)
	fmt.Printf("数组：底层数组指针：%d 数组指针：%d\n", unsafe.Pointer(&arr), unsafe.Pointer(&arr[0]))
	ArrayPointer(arr)
}

func SlicePointer(slice []int) {
	fmt.Printf("切片：底层数组指针：%d 切片：指针%v reflect.SliceHeader: %+v\n",
		unsafe.SliceData(slice), unsafe.Pointer(&slice), (*reflect.SliceHeader)(unsafe.Pointer(&slice)))
}

func ArrayPointer(arr [3]int) {
	fmt.Printf("数组：底层数组指针：%d 数组指针：%d\n", unsafe.Pointer(&arr), unsafe.Pointer(&arr[0]))
}

func TestModify(t *testing.T) {
	arr := [...]int{1, 2, 3, 4, 5, 6, 7}
	slice := arr[:]
	slice[4] = 8
	t.Logf("arr[4]=%v,slice[4]=%v\n", arr[4], slice[4])
	assert.Equal(t, slice[4], arr[4])
	slice = append(slice, 9)
	slice[5] = 10
	t.Logf("arr[4]=%v,slice[4]=%v\n", arr[4], slice[4])
	assert.Equal(t, slice[4], arr[4])
	t.Logf("arr[5]=%v,slice[5]=%v\n", arr[5], slice[5])
	assert.NotEqual(t, slice[5], arr[5])
}

func TestModifyTwoSlice(t *testing.T) {
	arr := [...]int{1, 2, 3, 4, 5, 6, 7, 8, 9}
	slice1 := arr[1:5]
	slice2 := arr[3:8]
	slice1[2] = 8
	t.Logf("%v %v %v\n", arr, slice1, slice2)
	assert.Equal(t, slice1[2], slice2[0], arr[3])
}

func TestCap(t *testing.T) {
	slice := []int{1, 2, 3, 4}
	fmt.Printf("len:%d cap: %d\n", len(slice), cap(slice))
	slice = append(slice, make([]int, 11)...)
	fmt.Printf("len:%d cap: %d\n", len(slice), cap(slice)) // oldcap<256，直接使用新切片容量
	slice = append(slice, make([]int, 260)...)
	fmt.Printf("len:%d cap: %d\n", len(slice), cap(slice)) // oldcap<256，直接使用新切片容量
	slice = append(slice, make([]int, 250)...)
	fmt.Printf("len:%d cap: %d\n", len(slice), cap(slice)) // 1.25倍循环扩容
}

func TestString(t *testing.T) {
	str := "hello"
	fmt.Printf("%d %+v\n", &str, (*reflect.StringHeader)(unsafe.Pointer(&str)))
	str = "world"
	fmt.Printf("%d %+v\n", &str, (*reflect.StringHeader)(unsafe.Pointer(&str)))
	str = str[:3]
	fmt.Printf("%d %+v\n", &str, (*reflect.StringHeader)(unsafe.Pointer(&str)))
}

func TestStringAsSlice(t *testing.T) {
	str := "hello,world"
	hello := str[:5]
	world := str[6:]
	fmt.Printf("%d %+v\n", &str, (*reflect.StringHeader)(unsafe.Pointer(&str)))
	fmt.Printf("%d %+v\n", &hello, (*reflect.StringHeader)(unsafe.Pointer(&hello)))
	fmt.Printf("%d %+v\n", &world, (*reflect.StringHeader)(unsafe.Pointer(&world)))
}

func TestCopy(t *testing.T) {
	str := "hello,world"
	fmt.Printf("%d %+v\n", &str, (*reflect.StringHeader)(unsafe.Pointer(&str)))
	b := []byte(str)
	fmt.Printf("%d %+v\n", unsafe.Pointer(&b), (*reflect.SliceHeader)(unsafe.Pointer(&b)))
}

func TestZeroCopy(t *testing.T) {
	str := "hello,world"
	fmt.Printf("%d %+v\n", &str, (*reflect.StringHeader)(unsafe.Pointer(&str)))
	b := unsafe.Slice(unsafe.StringData(str), len(str))
	fmt.Printf("%s %+v\n", b, (*reflect.SliceHeader)(unsafe.Pointer(&b)))
}

func TestConvertZeroCopy(t *testing.T) {
	n := []int64{1, 2, 3, 4}
	// 注意精度问题
	fmt.Printf("%+v\n", (*reflect.SliceHeader)(unsafe.Pointer(&n)))
	f := unsafe.Slice(unsafe.SliceData(n), len(n))
	fmt.Printf("%v %+v\n", f, (*reflect.SliceHeader)(unsafe.Pointer(&f)))
}

func TestReplace(t *testing.T) {
	str := "hello,world"
	fmt.Printf("%v %+v\n", str, (*reflect.StringHeader)(unsafe.Pointer(&str)))
	b := []byte(str)
	b[1] = 'a'
	str = unsafe.String(unsafe.SliceData(b), len(b))
	fmt.Printf("%v %+v\n", str, (*reflect.StringHeader)(unsafe.Pointer(&str)))
}
