package main

import (
	"testing"
)

// section: benchmarks

// BenchmarkAppendWithoutPreallocation demonstrates appending without pre-allocating capacity
func BenchmarkAppendWithoutPreallocation(b *testing.B) {
	for i := 0; i < b.N; i++ {
		b.StopTimer()
		slice := []int{}
		b.StartTimer()
		for j := 0; j < 1000; j++ {
			slice = append(slice, j)
		}
	}
}

// BenchmarkAppendWithPreallocation demonstrates appending with pre-allocated capacity
func BenchmarkAppendWithPreallocation(b *testing.B) {
	for i := 0; i < b.N; i++ {
		b.StopTimer()
		slice := make([]int, 0, 1000)
		b.StartTimer()
		for j := 0; j < 1000; j++ {
			slice = append(slice, j)
		}
	}
}

// BenchmarkAppendWithLength demonstrates using make with length (no append needed)
func BenchmarkAppendWithLength(b *testing.B) {
	for i := 0; i < b.N; i++ {
		b.StopTimer()
		slice := make([]int, 1000)
		b.StartTimer()
		for j := 0; j < 1000; j++ {
			slice[j] = j
		}
	}
}

// BenchmarkCapacityGrowth demonstrates how capacity grows when not pre-allocated
func BenchmarkCapacityGrowth_Small(b *testing.B) {
	for i := 0; i < b.N; i++ {
		b.StopTimer()
		slice := []int{}
		b.StartTimer()
		for j := 0; j < 100; j++ {
			slice = append(slice, j)
		}
	}
}

func BenchmarkCapacityGrowth_Medium(b *testing.B) {
	for i := 0; i < b.N; i++ {
		b.StopTimer()
		slice := []int{}
		b.StartTimer()
		for j := 0; j < 10000; j++ {
			slice = append(slice, j)
		}
	}
}

func BenchmarkCapacityGrowth_Large(b *testing.B) {
	for i := 0; i < b.N; i++ {
		b.StopTimer()
		slice := []int{}
		b.StartTimer()
		for j := 0; j < 100000; j++ {
			slice = append(slice, j)
		}
	}
}

// BenchmarkSliceCopy demonstrates copy performance
func BenchmarkSliceCopy_SmallSlice(b *testing.B) {
	source := make([]int, 100)
	for i := range source {
		source[i] = i
	}

	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		b.StopTimer()
		dest := make([]int, len(source))
		b.StartTimer()
		copy(dest, source)
	}
}

func BenchmarkSliceCopy_LargeSlice(b *testing.B) {
	source := make([]int, 100000)
	for i := range source {
		source[i] = i
	}

	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		b.StopTimer()
		dest := make([]int, len(source))
		b.StartTimer()
		copy(dest, source)
	}
}

// BenchmarkSliceIteration compares different iteration methods
func BenchmarkSliceIteration_Range(b *testing.B) {
	slice := make([]int, 10000)
	for i := range slice {
		slice[i] = i
	}

	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		sum := 0
		for _, v := range slice {
			sum += v
		}
		_ = sum
	}
}

func BenchmarkSliceIteration_Index(b *testing.B) {
	slice := make([]int, 10000)
	for i := range slice {
		slice[i] = i
	}

	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		sum := 0
		for j := 0; j < len(slice); j++ {
			sum += slice[j]
		}
		_ = sum
	}
}

func BenchmarkSliceIteration_LenCached(b *testing.B) {
	slice := make([]int, 10000)
	for i := range slice {
		slice[i] = i
	}

	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		sum := 0
		length := len(slice)
		for j := 0; j < length; j++ {
			sum += slice[j]
		}
		_ = sum
	}
}

// section: benchmarks
