You are an expert in writing code in many different languages. Your goal is to perform code completion for the following code, keeping in mind the rest of the code and the file meta data.
    Metadata details:
    filename: statistics.go
    path of file: ./repos/cel-go/vendor/github.com/antlr4-go/antlr/v4
    
    the code of the file until where you have to start completion: //go:build antlr.stats

package antlr

import (
	"fmt"
	"log"
	"os"
	"path/filepath"
	"sort"
	"strconv"
	"sync"
)

// This file allows the user to collect statistics about the runtime of the ANTLR runtime. It is not enabled by default
// and so incurs no time penalty. To enable it, you must build the runtime with the antlr.stats build tag.
//

// Tells various components to collect statistics - because it is only true when this file is included, it will
// allow the compiler to completely eliminate all the code that is only used when collecting statistics.
const collectStats = true

// goRunStats is a collection of all the various data the ANTLR runtime has collected about a particular run.
// It is exported so that it can be used by others to look for things that are not already looked for in the
// runtime statistics.
type goRunStats struct {

	// jStats is a slice of all the [JSta
    
func (s *goRunStats) reportCollections(dir, prefix string) {
	cname := filepath.Join(dir, ".asciidoctor")
	// If the file doesn't exist, create it, or append to the file
	f, err := os.OpenFile(cname, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
	if err != nil {
		log.Fatal(err)
	}
	_, _ = f.WriteString(`// .asciidoctorconfig
++++
<style>
body {
font-family: "Quicksand", "Montserrat", "Helvetica";
background-color: black;
}
</style>
++++`)
	_ = f.Close()

	fname := filepath.Join(dir, prefix+"_"+"_"+collectionsFile+"_"+".adoc")
	// If the file doesn't exist, create it, or append to the file
	f, err = os.OpenFile(fname, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
	if err != nil {
		log.Fatal(err)
	}
	defer func(f *os.File) {
		err := f.Close()
		if err != nil {
			log.Fatal(err)
		}
	}(f)
	_, _ = f.WriteString("= Collections for " + prefix + "\n\n")

	_, _ = f.WriteString("== Summary\n")

	if s.unusedCollections != nil {
		_, _ = f.WriteString("=== Unused Collections\n")
		_, _ = f.WriteString("Unused collections incur a penalty for allocation that makes them a candidate for either\n")
		_, _ = f.WriteString(" removal or optimization. If you are using a collection that is not used, you should\n")
		_, _ = f.WriteString(" consider removing it. If you are using a collection that is used, but not very often,\n")
		_, _ = f.WriteString(" you should consider using lazy initialization to defer the allocation until it is\n")
		_, _ = f.WriteString(" actually needed.\n\n")

		_, _ = f.WriteString("\n.Unused collections\n")
		_, _ = f.WriteString(`[cols="<3,>1"]` + "\n\n")
		_, _ = f.WriteString("|===\n")
		_, _ = f.WriteString("| Type | Count\n")

		for k, v := range s.unusedCollections {
			_, _ = f.WriteString("| " + CollectionDescriptors[k].SybolicName + " | " + strconv.Itoa(v) + "\n")
		}
		f.WriteString("|===\n\n")
	}

	_, _ = f.WriteString("\n.Summary of Collections\n")
	_, _ = f.WriteString(`[cols="<3,>1"]` + "\n\n")
	_, _ = f.WriteString("|===\n")
	_, _ = f.WriteString("| Type | Count\n")
	for k, v := range s.counts {
		_, _ = f.WriteString("| " + CollectionDescriptors[k].SybolicName + " | " + strconv.Itoa(v) + "\n")
	}
	_, _ = f.WriteString("| Total | " + strconv.Itoa(len(s.jStats)) + "\n")
	_, _ = f.WriteString("|===\n\n")

	_, _ = f.WriteString("\n.Summary of Top " + strconv.Itoa(s.topN) + " Collections by MaxSize\n")
	_, _ = f.WriteString(`[cols="<1,<3,>1,>1,>1,>1"]` + "\n\n")
	_, _ = f.WriteString("|===\n")
	_, _ = f.WriteString("| Source | Description | MaxSize | EndSize | Puts | Gets\n")
	for _, c := range s.topNByMax {
		_, _ = f.WriteString("| " + CollectionDescriptors[c.Source].SybolicName + "\n")
		_, _ = f.WriteString("| " + c.Description + "\n")
		_, _ = f.WriteString("| " + strconv.Itoa(c.MaxSize) + "\n")
		_, _ = f.WriteString("| " + strconv.Itoa(c.CurSize) + "\n")
		_, _ = f.WriteString("| " + strconv.Itoa(c.Puts) + "\n")
		_, _ = f.WriteString("| " + strconv.Itoa(c.Gets) + "\n")
		_, _ = f.WriteString("\n")
	}
	_, _ = f.WriteString("|===\n\n")

	_, _ = f.WriteString("\n.Summary of Top " + strconv.Itoa(s.topN) + " Collections by Access\n")
	_, _ = f.WriteString(`[cols="<1,<3,>1,>1,>1,>1,>1"]` + "\n\n")
	_, _ = f.WriteString("|===\n")
	_, _ = f.WriteString("| Source | Description | MaxSize | EndSize | Puts | Gets | P+G\n")
	for _, c := range s.topNByUsed {
		_, _ = f.WriteString("| " + CollectionDescriptors[c.Source].SybolicName + "\n")
		_, _ = f.WriteString("| " + c.Description + "\n")
		_, _ = f.WriteString("| " + strconv.Itoa(c.MaxSize) + "\n")
		_, _ = f.WriteString("| " + strconv.Itoa(c.CurSize) + "\n")
		_, _ = f.WriteString("| " + strconv.Itoa(c.Puts) + "\n")
		_, _ = f.WriteString("| " + strconv.Itoa(c.Gets) + "\n")
		_, _ = f.WriteString("| " + strconv.Itoa(c.Gets+c.Puts) + "\n")
		_, _ = f.WriteString("\n")
	}
	_, _ = f.WriteString("|===\n\n")
}