package main

import (
	"fmt"
)

func main() {
	fmt.Println("PIZZA!!!")
	pizza()
}

func printSlice(s []int, name string) {
	fmt.Println("slice", name, s, "len:", len(s), "cap:", cap(s))
}

func pizzaCpy(dst, src []int) {
	// NOTE we don't have to return a slice here (or take a slice ptr)
	// as we only modify the data the dst slice points to
	// without causing re-allocation etc.
	n := len(dst)
	if len(dst) > len(src) {
		n = len(src)
	}
	// NOTE 2: as opposed to stdlib copy, dst and src must NOT overlap!
	for i := 0; i < n; i++ {
		dst[i] = src[i]
	}
}

func pizza() {
	a := []int{0, 1, 2, 3}
	printSlice(a, "a")

	aCpy := make([]int, len(a), 128)
	printSlice(aCpy, "acpy")

	pizzaCpy(aCpy, a)

	printSlice(aCpy, "acpy")
	printSlice(a, "a")

	fmt.Println("loop")
	// if ACAP >= ITERS, the first elem of the underlying a-data will be 42 later
	// as appending won't re-allocate the underlying data buffer
	const (
		ACAP  = 4
		ITERS = 8
	)
	a = make([]int, 0, ACAP)
	b := a
	printSlice(a, "a")
	printSlice(b, "b")

	// if ACAP < ITERS, then a and b's slice headers will point to different data
	// as soon as re-alloc happens (when len(a) == cap(a) and we append)
	for i := 0; i < ITERS; i++ {
		a = append(a, i)
		printSlice(a, "a")
	}

	printSlice(b, "b")
	printSlice(b[:cap(b)], "b[:cap(b)]")
	b = append(b, 42)
	b = b[:cap(b)]
	printSlice(b, "b")
	printSlice(a, "a")
}
