package main

import (
	"testing"
	"unsafe"
)

// Большая структура для теста
type BigStruct struct {
	A, B, C, D, E, F, G, H, I, J float64
}

// Обычные функции для слайсов структур
func ToPtrsStruct(s []BigStruct) []*BigStruct {
	res := make([]*BigStruct, len(s))
	for i := range s {
		res[i] = &s[i]
	}
	return res
}

func DerefSliceStruct(s []*BigStruct) []BigStruct {
	res := make([]BigStruct, len(s))
	for i := range s {
		if s[i] != nil {
			res[i] = *s[i]
		}
	}
	return res
}

// Unsafe версии
func ToPtrsStructUnsafe(s []BigStruct) []*BigStruct {
	n := len(s)
	res := make([]*BigStruct, n)
	if n == 0 {
		return res
	}
	base := unsafe.Pointer(&s[0])
	size := unsafe.Sizeof(s[0])
	for i := 0; i < n; i++ {
		res[i] = (*BigStruct)(unsafe.Pointer(uintptr(base) + uintptr(i)*size))
	}
	return res
}

func DerefSliceStructUnsafe(s []*BigStruct) []BigStruct {
	n := len(s)
	res := make([]BigStruct, n)
	if n == 0 {
		return res
	}
	baseDst := unsafe.Pointer(&res[0])
	size := unsafe.Sizeof(res[0])
	for i := 0; i < n; i++ {
		src := unsafe.Pointer(s[i])
		dst := unsafe.Pointer(uintptr(baseDst) + uintptr(i)*size)
		*(*BigStruct)(dst) = *(*BigStruct)(src)
	}
	return res
}

// === Бенчмарки ===
func BenchmarkToPtrsStruct(b *testing.B) {
	data := make([]BigStruct, 1_000_000)
	for i := range data {
		data[i] = BigStruct{float64(i), float64(i), float64(i), float64(i),
			float64(i), float64(i), float64(i), float64(i), float64(i), float64(i)}
	}
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		_ = ToPtrsStruct(data)
	}
}

func BenchmarkToPtrsStructUnsafe(b *testing.B) {
	data := make([]BigStruct, 1_000_000)
	for i := range data {
		data[i] = BigStruct{float64(i), float64(i), float64(i), float64(i),
			float64(i), float64(i), float64(i), float64(i), float64(i), float64(i)}
	}
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		_ = ToPtrsStructUnsafe(data)
	}
}

func BenchmarkDerefSliceStruct(b *testing.B) {
	data := make([]BigStruct, 1_000_000)
	for i := range data {
		data[i] = BigStruct{float64(i), float64(i), float64(i), float64(i),
			float64(i), float64(i), float64(i), float64(i), float64(i), float64(i)}
	}
	ptrs := ToPtrsStruct(data)
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		_ = DerefSliceStruct(ptrs)
	}
}

func BenchmarkDerefSliceStructUnsafe(b *testing.B) {
	data := make([]BigStruct, 1_000_000)
	for i := range data {
		data[i] = BigStruct{float64(i), float64(i), float64(i), float64(i),
			float64(i), float64(i), float64(i), float64(i), float64(i), float64(i)}
	}
	ptrs := ToPtrsStruct(data)
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		_ = DerefSliceStructUnsafe(ptrs)
	}
}
