summaryrefslogtreecommitdiffstats
path: root/src/internal/coverage/stringtab/stringtab.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/internal/coverage/stringtab/stringtab.go')
-rw-r--r--src/internal/coverage/stringtab/stringtab.go139
1 files changed, 139 insertions, 0 deletions
diff --git a/src/internal/coverage/stringtab/stringtab.go b/src/internal/coverage/stringtab/stringtab.go
new file mode 100644
index 0000000..156c8ad
--- /dev/null
+++ b/src/internal/coverage/stringtab/stringtab.go
@@ -0,0 +1,139 @@
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package stringtab
+
+import (
+ "fmt"
+ "internal/coverage/slicereader"
+ "internal/coverage/uleb128"
+ "io"
+)
+
+// This package implements string table writer and reader utilities,
+// for use in emitting and reading/decoding coverage meta-data and
+// counter-data files.
+
+// Writer implements a string table writing utility.
+type Writer struct {
+ stab map[string]uint32
+ strs []string
+ tmp []byte
+ frozen bool
+}
+
+// InitWriter initializes a stringtab.Writer.
+func (stw *Writer) InitWriter() {
+ stw.stab = make(map[string]uint32)
+ stw.tmp = make([]byte, 64)
+}
+
+// Nentries returns the number of strings interned so far.
+func (stw *Writer) Nentries() uint32 {
+ return uint32(len(stw.strs))
+}
+
+// Lookup looks up string 's' in the writer's table, adding
+// a new entry if need be, and returning an index into the table.
+func (stw *Writer) Lookup(s string) uint32 {
+ if idx, ok := stw.stab[s]; ok {
+ return idx
+ }
+ if stw.frozen {
+ panic("internal error: string table previously frozen")
+ }
+ idx := uint32(len(stw.strs))
+ stw.stab[s] = idx
+ stw.strs = append(stw.strs, s)
+ return idx
+}
+
+// Size computes the memory in bytes needed for the serialized
+// version of a stringtab.Writer.
+func (stw *Writer) Size() uint32 {
+ rval := uint32(0)
+ stw.tmp = stw.tmp[:0]
+ stw.tmp = uleb128.AppendUleb128(stw.tmp, uint(len(stw.strs)))
+ rval += uint32(len(stw.tmp))
+ for _, s := range stw.strs {
+ stw.tmp = stw.tmp[:0]
+ slen := uint(len(s))
+ stw.tmp = uleb128.AppendUleb128(stw.tmp, slen)
+ rval += uint32(len(stw.tmp)) + uint32(slen)
+ }
+ return rval
+}
+
+// Write writes the string table in serialized form to the specified
+// io.Writer.
+func (stw *Writer) Write(w io.Writer) error {
+ wr128 := func(v uint) error {
+ stw.tmp = stw.tmp[:0]
+ stw.tmp = uleb128.AppendUleb128(stw.tmp, v)
+ if nw, err := w.Write(stw.tmp); err != nil {
+ return fmt.Errorf("writing string table: %v", err)
+ } else if nw != len(stw.tmp) {
+ return fmt.Errorf("short write emitting stringtab uleb")
+ }
+ return nil
+ }
+ if err := wr128(uint(len(stw.strs))); err != nil {
+ return err
+ }
+ for _, s := range stw.strs {
+ if err := wr128(uint(len(s))); err != nil {
+ return err
+ }
+ if nw, err := w.Write([]byte(s)); err != nil {
+ return fmt.Errorf("writing string table: %v", err)
+ } else if nw != len([]byte(s)) {
+ return fmt.Errorf("short write emitting stringtab")
+ }
+ }
+ return nil
+}
+
+// Freeze sends a signal to the writer that no more additions are
+// allowed, only lookups of existing strings (if a lookup triggers
+// addition, a panic will result). Useful as a mechanism for
+// "finalizing" a string table prior to writing it out.
+func (stw *Writer) Freeze() {
+ stw.frozen = true
+}
+
+// Reader is a helper for reading a string table previously
+// serialized by a Writer.Write call.
+type Reader struct {
+ r *slicereader.Reader
+ strs []string
+}
+
+// NewReader creates a stringtab.Reader to read the contents
+// of a string table from 'r'.
+func NewReader(r *slicereader.Reader) *Reader {
+ str := &Reader{
+ r: r,
+ }
+ return str
+}
+
+// Read reads/decodes a string table using the reader provided.
+func (str *Reader) Read() {
+ numEntries := int(str.r.ReadULEB128())
+ str.strs = make([]string, 0, numEntries)
+ for idx := 0; idx < numEntries; idx++ {
+ slen := str.r.ReadULEB128()
+ str.strs = append(str.strs, str.r.ReadString(int64(slen)))
+ }
+}
+
+// Entries returns the number of decoded entries in a string table.
+func (str *Reader) Entries() int {
+ return len(str.strs)
+}
+
+// Get returns string 'idx' within the string table.
+func (str *Reader) Get(idx uint32) string {
+ return str.strs[idx]
+}